Fork me on GitHub
#holy-lambda
<
2021-11-02
>
steveb8n21:11:29

is anyone using Carmine with HL (or even non-native Lambda?)

Karol Wójcik21:11:59

Never used carmine before? What questions regarding Carmine you do have?

steveb8n23:11:12

more an AWS question: how to access Redis from a HL lambda outside the VPC

steveb8n23:11:39

current solution is use another HL lambda inside the VPC and invoke it from the outer lambda

steveb8n23:11:15

this will work for me but it would be nice not to need the inner lambda

Karol Wójcik05:11:07

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?

Karol Wójcik05:11:25

If yes you would need NAT Gateway for that.

steveb8n05:11:26

turns out I don’t. a lambda outside a VPC can call a lambda inside a VPC without NAT.

steveb8n05:11:37

since NAT is expensive, this is a good solution

steveb8n05:11:56

and using native lambdas on both sides makes it fast/cheap

steveb8n05:11:35

I suppose a lambda call using ARN doesn’t use DNS i.e. doesn’t need NAT

steveb8n05:11:43

works for me in prod already

steveb8n05:11:23

another good use-case for HL

steveb8n05:11:17

lambda on inside that talks to Redis runs in 5ms i.e. very cheap

Karol Wójcik05:11:32

If that's the case it will cost you additional 30$.

Karol Wójcik05:11:47

I mean for NAT Gateway.

Karol Wójcik05:11:04

Why does the Redis is not in the VPC?

steveb8n05:11:27

Redis only runs in a VPC, not allowed outside

steveb8n05:11:44

but I have internet facing lambdas that need to use the cache

steveb8n05:11:24

I’ll keep an eye on costs. if inner lambda costs a lot, I’ll switch to NAT gateway

steveb8n05:11:49

I don’t think it will cost a lot

Karol Wójcik05:11:51

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.

Karol Wójcik05:11:17

It will certainly not cost more

steveb8n05:11:20

yep, that’s it

steveb8n05:11:34

HL is a NAT gateway alternative

Karol Wójcik05:11:20

So you have a native lambdas that call native lambda to get the cache :D

steveb8n05:11:23

some extra code because it’s Carmine api inside VPC and transit (or nippy) when sent to outside

steveb8n05:11:28

but that’s easy to write/test

steveb8n05:11:41

CDK makes setup easy too

Karol Wójcik05:11:44

Yeah cool. However there might be a case your cache will be called to frequently, so expect some cold starts there.

steveb8n06:11:32

I’ve got a custom pinger that reduces cold starts. only scale up cold starts happen now

Karol Wójcik07:11:36

Doesn't the reserved concurrency work the same? Asking, because I'm curious

steveb8n07:11:33

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

steveb8n07:11:10

hmmm: Carmine isn’t well suited to HL. It’s a macro at it’s core https://github.com/ptaoussanis/carmine#connections

steveb8n07:11:28

I can’t see how that will work with native

Karol Wójcik07:11:13

Why you think it would not work?

Karol Wójcik07:11:23

Macro expands during compilation then plain java classes are compiled

Karol Wójcik07:11:44

Btw are you using other runtimes/languages for Lambda as well? Or only HL and Native?

steveb8n08:11:13

because the connection spec i.e. hostname is not known at compile time. it’s in the lambda env

steveb8n08:11:55

I suppose I could hardcode a lookup for all the hostnames so it is known at compile time and not use env vars

steveb8n08:11:29

I already tested interop with the Jedis lib so I can fallback to https://github.com/tolitius/obiwan

Karol Wójcik08:11:00

And? I mean. It doesn't matter. Macro expands at compile time

steveb8n08:11:08

plus I don’t need/want a connection pool in a Lambda env. it’s effectively single threaded so only 1 connection required

Karol Wójcik08:11:38

I could be of course mistaken. Anyway to the last one I agree. You don't want a pool in AWS Lambda

steveb8n08:11:05

yeah: env values in HL context are runtime. thus can’t use them to control the connection pool

Karol Wójcik08:11:26

But envs are also readable without the ctx

Karol Wójcik08:11:31

System/getenv to the rescue

Karol Wójcik08:11:43

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?

Karol Wójcik08:11:52

But yeah. System/getenv is probably what you do want

steveb8n08:11:02

oh. I didn’t know that lambda env vars could be read that way. thanks. I’ll try it

Karol Wójcik08:11:24

Yes you can. Actually envs are there, since it's easier to provide native-agent-payloads that way, or in general test the lambdas.

Karol Wójcik08:11:51

But yeah. HL afterwards is all about Java/Clojure 😄

steveb8n08:11:43

native:conf fails with an NPE when Carmine is used

steveb8n09:11:12

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)

steveb8n09:11:27

I think I’ll use obiwan instead. no macros required

Karol Wójcik09:11:28

What GraalVM version?

Karol Wójcik09:11:49

Yeah, but what image builder

steveb8n09:11:15

don’t worry about it. Jedis/Obiwan is simpler and easier for the HL use-case

Karol Wójcik09:11:15

Yeah. But still you should upgrade 😄 I really mean it. There are new images with GraalVM native-image with various variants.

Karol Wójcik09:11:36

0.6.2 is a way better release. Very close to how stable I want HL to be.

Karol Wójcik09:11:04

But yeah. Starting from 0.5.0 I promised myself to do as little breaking changes as it's only possible

Karol Wójcik09:11:25

Also 0.6.2 doesn't puts all the artifacts in local directory (which means your CI will see a speedup)

steveb8n09:11:28

I’ve been meaning to ask about upgrading. My hope is that it will use less mem for native:executable?

steveb8n09:11:41

my CI still intermittently runs out of mem

Karol Wójcik09:11:20

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.

steveb8n09:11:51

I’ll start with upgrade for now

steveb8n09:11:01

then I’ll look into ARM later

steveb8n09:11:21

got too much to do so I need to not keep chasing new stuff

Karol Wójcik09:11:29

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

Karol Wójcik09:11:37

Yeah totally got your point 🙂

steveb8n09:11:49

cool. I’ll try it tomorrow and will let you know

steveb8n09:11:59

stopping work now. have a good day

Karol Wójcik09:11:25

Wish you the same 🙂 In case of any issues you know where to find me. All the best!

Michael W23:11:22

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"})))

steveb8n23:11:14

that normally means you haven’t captured enough using agent/in-context or using sample requests

steveb8n23:11:43

are you calling SSM successfully in native:conf step?

Michael W23:11:42

That is the error I get from hl:native:conf

Michael W23:11:46

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.

Michael W00:11:45

(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))))

Michael W00:11:16

Formatter is crap but that's the whole lambda

steveb8n00:11:17

personally I find it easier to build a mock for aws api requests and use that in conf handling.

steveb8n00:11:11

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

Karol Wójcik05:11:53

I will try your example. Could you paste the entire namespace, and your deps.edn?

Karol Wójcik05:11:39

Anyway I can second what @U0510KXTU 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.

Karol Wójcik07:11:05

@UAB2NMK25 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 @ssm

Karol Wójcik07:11:03

bb hl:native:conf calls a regular JVM Java with tracing, therefore if it fails you have 99% chance it's issue with you code.

Karol Wójcik07:11:47

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))
    ))

Michael W15:11:14

This works for hl:native:conf but fails for hl:native:executable with: jdk.xml.internal.SecuritySupport was unintentionally initialized at build time.

Karol Wójcik15:11:55

So initialize jdk.xml.internal at build time.

Karol Wójcik15:11:37

—initialize-at-build-time=jdk.xml.internal @UAB2NMK25

Michael W16:11:05

Sorry I'm newish to this whole thing, where do I do that? Is that an option I add to the bb command?

Karol Wójcik16:11:44

Put it in :native-image-args in bb.edn

Karol Wójcik16:11:11

There will be an additional error as far as I can remember

Michael W16:11:14

Doh, I checked deps.edn forgot bb.edn is a thing.

Karol Wójcik16:11:01

I will document the common ways of dealing with native-image errors. https://fierycod.github.io/holy-lambda/#/native-backend

Michael W16:11:43

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?

Karol Wójcik16:11:28

You can do both

Karol Wójcik16:11:23

You’re very close to getting it working.

Michael W16:11:29

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)

Michael W16:11:03

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.

Michael W16:11:02

It got much further in compilation, I think it was very close to the end.

Michael W16:11:30

I really appreciate the help on troubleshooting this.

Karol Wójcik16:11:38

Not enough memory

Michael W16:11:51

I actually did increase the ram to 4GB, I'll go to 6GB and try again.

Karol Wójcik16:11:56

At least 6gb. But if you wanna be safe increase to 8gb

Michael W16:11:18

Sweet, it compiled!

Michael W16:11:34

And it pulled the password from ssm. Thanks very much for the help.

Michael W16:11:00

I'm going to play around with the awssdk example now, see if I can compare the 2.

Karol Wójcik16:11:05

You’re very welcome