is anyone using Carmine with HL (or even non-native Lambda?)
Doesn't the reserved concurrency work the same? Asking, because I'm curious
yes but it’s $40/month per lambda version. I use many versions so that adds up pretty quick. instead I track recent use of versions and keep those alive with a HL lambda
hmmm: Carmine isn’t well suited to HL. It’s a macro at it’s core https://github.com/ptaoussanis/carmine#connections
I can’t see how that will work with native
Why you think it would not work?
Macro expands during compilation then plain java classes are compiled
Btw are you using other runtimes/languages for Lambda as well? Or only HL and Native?
because the connection spec i.e. hostname is not known at compile time. it’s in the lambda env
I suppose I could hardcode a lookup for all the hostnames so it is known at compile time and not use env vars
I already tested interop with the Jedis lib so I can fallback to https://github.com/tolitius/obiwan
And? I mean. It doesn't matter. Macro expands at compile time
plus I don’t need/want a connection pool in a Lambda env. it’s effectively single threaded so only 1 connection required
I could be of course mistaken. Anyway to the last one I agree. You don't want a pool in AWS Lambda
yeah: env values in HL context are runtime. thus can’t use them to control the connection pool
But envs are also readable without the ctx
System/getenv to the rescue
You can create a connection on init step 🙂 Or you can initialize the connection in Lambda if you really want, but do it only once in an atom?
But yeah. System/getenv is probably what you do want
oh. I didn’t know that lambda env vars could be read that way. thanks. I’ll try it
Yes you can. Actually envs are there, since it's easier to provide native-agent-payloads that way, or in general test the lambdas.
But yeah. HL afterwards is all about Java/Clojure 😄
native:conf fails with an NPE when Carmine is used
NPE?
Fatal error: java.lang.NullPointerException: null
at com.oracle.svm.agent.tracing.TraceFileWriter.printValue(TraceFileWriter.java:103)
at com.oracle.svm.agent.tracing.TraceFileWriter.printArray(TraceFileWriter.java:92)
at com.oracle.svm.agent.tracing.TraceFileWriter.traceEntry(TraceFileWriter.java:68)
at com.oracle.svm.agent.tracing.core.Tracer.traceCall(Tracer.java:117)
at com.oracle.svm.agent.BreakpointInterceptor.traceBreakpoint(BreakpointInterceptor.java:150)
at com.oracle.svm.agent.BreakpointInterceptor.handleGetMethod(BreakpointInterceptor.java:332)
at com.oracle.svm.agent.BreakpointInterceptor.getDeclaredMethod(BreakpointInterceptor.java:311)
at com.oracle.svm.agent.BreakpointInterceptor.onBreakpoint(BreakpointInterceptor.java:957)
at com.oracle.svm.jni.nativeapi.JNIFunctionPointerTypes$GetMethodIDFunctionPointer.invoke(JNIFunctionPointerTypes.java:-1)
at com.oracle.svm.agent.JniCallInterceptor.getStaticMethodID(JniCallInterceptor.java:163)I think I’ll use obiwan instead. no macros required
What GraalVM version?
HL 0.5.0
Yeah, but what image builder
don’t worry about it. Jedis/Obiwan is simpler and easier for the HL use-case
Yeah. But still you should upgrade 😄 I really mean it. There are new images with GraalVM native-image with various variants.
0.6.2 is a way better release. Very close to how stable I want HL to be.
But yeah. Starting from 0.5.0 I promised myself to do as little breaking changes as it's only possible
Also 0.6.2 doesn't puts all the artifacts in local directory (which means your CI will see a speedup)
I’ve been meaning to ask about upgrading. My hope is that it will use less mem for native:executable?
my CI still intermittently runs out of mem
It should both use less memory, compile faster, and also produce smaller artifact. Btw don't you want to use the local agent for CI? That way you would benefit from ARM64. Much better cold starts, faster compile time, better price per 1M invocation.
I’ll start with upgrade for now
then I’ll look into ARM later
got too much to do so I need to not keep chasing new stuff
Yeah. You can generate a new project and just compare the changes or follow the migration guide: https://fierycod.github.io/holy-lambda/#/migration-guide
Yeah totally got your point 🙂
cool. I’ll try it tomorrow and will let you know
stopping work now. have a good day
Wish you the same 🙂 In case of any issues you know where to find me. All the best!
🙏
Never used carmine before? What questions regarding Carmine you do have?
more an AWS question: how to access Redis from a HL lambda outside the VPC
current solution is use another HL lambda inside the VPC and invoke it from the outer lambda
this will work for me but it would be nice not to need the inner lambda
Wait. Hmm. As I understand you have a Lambda that is in VPC (probably private one) and you would like to call the service that is publicly available?
If yes you would need NAT Gateway for that.
turns out I don’t. a lambda outside a VPC can call a lambda inside a VPC without NAT.
since NAT is expensive, this is a good solution
and using native lambdas on both sides makes it fast/cheap
I suppose a lambda call using ARN doesn’t use DNS i.e. doesn’t need NAT
works for me in prod already
another good use-case for HL
lambda on inside that talks to Redis runs in 5ms i.e. very cheap
If that's the case it will cost you additional 30$.
I mean for NAT Gateway.
Why does the Redis is not in the VPC?
Redis only runs in a VPC, not allowed outside
but I have internet facing lambdas that need to use the cache
I’ll keep an eye on costs. if inner lambda costs a lot, I’ll switch to NAT gateway
I don’t think it will cost a lot
Ok got it. So you would need the NAT for those lambdas that connect to outer world. Otherwise putting all the lambdas in VPC is a good idea.
It will certainly not cost more
yep, that’s it
HL is a NAT gateway alternative
So you have a native lambdas that call native lambda to get the cache :D
exactly
some extra code because it’s Carmine api inside VPC and transit (or nippy) when sent to outside
but that’s easy to write/test
CDK makes setup easy too
Yeah cool. However there might be a case your cache will be called to frequently, so expect some cold starts there.
I’ve got a custom pinger that reduces cold starts. only scale up cold starts happen now
Any idea how to deal with this error:
Exception in agent-context: #error {
:cause No implementation of method: :-get-info of protocol: #'cognitect.aws.client/ClientSPI found for class: clojure.lang.Delay
I am trying to access secrets from aws ssm using aws-api from cognitect.
I am running the latest holy-lambda, 0.6.2. This works using the babashka aws-api pod, but gives that error when I try to compile native.
(def ssm (delay (aws/client {:api :ssm
:region "us-west-2"})))@michael819 You have a typo in your example.
(agent/in-context
(let [ddipass (aws/invoke ssm {:op :GetParameter
:request {:Name "ddi-api-password"
:WithDecryption true}})]
(println (pprint ddipass))))
You have to reference the ssm @ssmbb hl:native:conf calls a regular JVM Java with tracing, therefore if it fails you have 99% chance it's issue with you code.
Deps.edn
{:deps {org.clojure/clojure {:mvn/version "1.10.3"}
io.github.FieryCod/holy-lambda {:mvn/version "0.6.2"}
com.github.clj-easy/graal-build-time {:mvn/version "0.1.4"}
com.cognitect.aws/api {:mvn/version "0.8.524"}
com.cognitect.aws/endpoints {:mvn/version "1.1.12.93"}
com.cognitect.aws/ssm {:mvn/version "814.2.1008.0"}}
:paths ["src" "resources"]
:aliases {:uberjar {:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.1.303"}}
:exec-fn hf.depstar/uberjar
:exec-args {:aot ["example.core"]
:main-class "example.core"
:jar ".holy-lambda/build/output.jar"
:jvm-opts ["-Dclojure.compiler.direct-linking=true"
"-Dclojure.spec.skip-macros=true"]}}}}
core.cljc
(ns example.core
(:gen-class)
(:require
[cognitect.aws.http.cognitect]
[cognitect.aws.protocols.query]
[cognitect.aws.protocols.json]
[cognitect.aws.protocols.common]
[cognitect.aws.protocols.rest]
[cognitect.aws.protocols.rest-xml]
[cognitect.aws.client.api :as aws]
[fierycod.holy-lambda.response :as hr]
[fierycod.holy-lambda.agent :as agent]
[fierycod.holy-lambda.core :as h]))
(def ssm (delay (aws/client {:api :ssm
:region "eu-central-1"})))
(defn ExampleLambda
[{:keys [event ctx] :as request}]
(let [ddipass (aws/invoke @ssm {:op :GetParameter
:request {:Name "ddi-api-password"
:withDecryption true}})]
(hr/json {:event event
:ddipass ddipass})))
(h/entrypoint [#'ExampleLambda])
(agent/in-context
(let [ddipass (aws/invoke @ssm {:op :GetParameter
:request {:Name "ddi-api-password"
:WithDecryption true}})]
(println ddipass)
;; (println (pprint ddipass))
))This works for hl:native:conf but fails for hl:native:executable with: jdk.xml.internal.SecuritySupport was unintentionally initialized at build time.
So initialize jdk.xml.internal at build time.
—initialize-at-build-time=jdk.xml.internal @michael819
Sorry I'm newish to this whole thing, where do I do that? Is that an option I add to the bb command?
Put it in :native-image-args in bb.edn
There will be an additional error as far as I can remember
Doh, I checked deps.edn forgot bb.edn is a thing.
I will document the common ways of dealing with native-image errors. https://fierycod.github.io/holy-lambda/#/native-backend
Ok got further it wants some apache libs now. How to add multiple libraries to --initialize-at-build-time? comma seperated list? A whole new --initialize line?
You can do both
Congrats. ;)
You’re very close to getting it working.
Error: Image build request failed with exit status 137
com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 137
at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1762)
at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1473)
at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1434)
at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1421)In the past the errors have kinda given me a pointer, but that one is just flat, no pointer to a file to get more details.
It got much further in compilation, I think it was very close to the end.
I really appreciate the help on troubleshooting this.
Not enough memory
I actually did increase the ram to 4GB, I'll go to 6GB and try again.
At least 6gb. But if you wanna be safe increase to 8gb
Ok
Sweet, it compiled!
And it pulled the password from ssm. Thanks very much for the help.
I'm going to play around with the awssdk example now, see if I can compare the 2.
You’re very welcome
that normally means you haven’t captured enough using agent/in-context or using sample requests
are you calling SSM successfully in native:conf step?
That is the error I get from hl:native:conf
I only have this 1 call in the agent context and the lambda function. I have to get the pass word from ssm to do my actual work.
(def ssm (delay (aws/client {:api :ssm
:region "us-west-2"})))
(defn TestAPI
"Test DDI API"
[{:keys [event ctx] :as request}]
(let [ddipass (aws/invoke @ssm {:op :GetParameter
:request {:Name "ddi-api-password"
:withDecryption true}})]
(hr/json {:event event
:ddipass ddipass})))
(h/entrypoint [#'TestAPI])
(agent/in-context
(let [ddipass (aws/invoke ssm {:op :GetParameter
:request {:Name "ddi-api-password"
:WithDecryption true}})]
(println (pprint ddipass))))Formatter is crap but that's the whole lambda
personally I find it easier to build a mock for aws api requests and use that in conf handling.
often it’s easier to have a mocked aws call in an agent/in-context call than a real call. it still uses all the classes and conf catches it all
I will try your example. Could you paste the entire namespace, and your deps.edn?
Anyway I can second what @steveb8n said. Using official AWS SDK V2 has numerous benefits over cognitect AWS api: • you can mock your functions • X-ray is there • Works better with graalVM native-image • The performance is better • Artifact is smaller I will probably work on making a lite version of AWS Cognitect API that is both faster and GraalVM native-image friendly for clj-easy organization, but this will take a while.