holy-lambda

steveb8n 2021-11-02T21:24:29.015500Z

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

Karol Wójcik 2021-11-03T07:03:36.046100Z

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

steveb8n 2021-11-03T07:30:33.047Z

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

steveb8n 2021-11-03T07:31:10.047200Z

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

steveb8n 2021-11-03T07:31:28.047500Z

I can’t see how that will work with native

Karol Wójcik 2021-11-03T07:36:13.047900Z

Why you think it would not work?

Karol Wójcik 2021-11-03T07:37:23.049200Z

Macro expands during compilation then plain java classes are compiled

Karol Wójcik 2021-11-03T07:45:44.049400Z

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

steveb8n 2021-11-03T08:04:13.049600Z

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

steveb8n 2021-11-03T08:04:55.049800Z

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

steveb8n 2021-11-03T08:05:29.050Z

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

Karol Wójcik 2021-11-03T08:06:00.050300Z

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

steveb8n 2021-11-03T08:06:08.050500Z

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ójcik 2021-11-03T08:07:38.050700Z

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

steveb8n 2021-11-03T08:08:05.050900Z

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

Karol Wójcik 2021-11-03T08:09:26.051100Z

But envs are also readable without the ctx

Karol Wójcik 2021-11-03T08:09:31.051300Z

System/getenv to the rescue

Karol Wójcik 2021-11-03T08:10:43.051600Z

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ójcik 2021-11-03T08:10:52.051800Z

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

steveb8n 2021-11-03T08:28:02.052Z

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

Karol Wójcik 2021-11-03T08:31:24.052200Z

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ójcik 2021-11-03T08:31:51.052400Z

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

steveb8n 2021-11-03T08:58:43.061100Z

native:conf fails with an NPE when Carmine is used

Karol Wójcik 2021-11-03T08:59:09.061300Z

NPE?

steveb8n 2021-11-03T09:00:12.061500Z

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)

steveb8n 2021-11-03T09:00:27.061700Z

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

Karol Wójcik 2021-11-03T09:00:28.061900Z

What GraalVM version?

steveb8n 2021-11-03T09:00:41.062100Z

HL 0.5.0

Karol Wójcik 2021-11-03T09:00:49.062300Z

Yeah, but what image builder

steveb8n 2021-11-03T09:01:15.062500Z

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

Karol Wójcik 2021-11-03T09:02:15.062700Z

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

Karol Wójcik 2021-11-03T09:02:36.062900Z

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

Karol Wójcik 2021-11-03T09:03:04.063100Z

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

Karol Wójcik 2021-11-03T09:03:25.063300Z

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

steveb8n 2021-11-03T09:03:28.063500Z

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

steveb8n 2021-11-03T09:03:41.063700Z

my CI still intermittently runs out of mem

Karol Wójcik 2021-11-03T09:05:20.063900Z

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.

steveb8n 2021-11-03T09:05:51.064200Z

I’ll start with upgrade for now

steveb8n 2021-11-03T09:06:01.064400Z

then I’ll look into ARM later

steveb8n 2021-11-03T09:06:21.064600Z

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

Karol Wójcik 2021-11-03T09:06:29.064800Z

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ójcik 2021-11-03T09:06:37.065100Z

Yeah totally got your point 🙂

steveb8n 2021-11-03T09:06:49.065300Z

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

steveb8n 2021-11-03T09:06:59.065500Z

stopping work now. have a good day

Karol Wójcik 2021-11-03T09:07:25.065700Z

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

steveb8n 2021-11-03T09:07:57.065900Z

🙏

Karol Wójcik 2021-11-02T21:47:59.016800Z

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

steveb8n 2021-11-02T23:22:12.017400Z

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

steveb8n 2021-11-02T23:22:39.017600Z

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

steveb8n 2021-11-02T23:23:15.017800Z

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

Karol Wójcik 2021-11-03T05:16:07.033500Z

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ójcik 2021-11-03T05:16:25.034200Z

If yes you would need NAT Gateway for that.

steveb8n 2021-11-03T05:25:26.034400Z

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

steveb8n 2021-11-03T05:25:37.034600Z

since NAT is expensive, this is a good solution

steveb8n 2021-11-03T05:25:56.034800Z

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

steveb8n 2021-11-03T05:27:35.035Z

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

steveb8n 2021-11-03T05:27:43.035200Z

works for me in prod already

steveb8n 2021-11-03T05:28:23.035400Z

another good use-case for HL

steveb8n 2021-11-03T05:29:17.036200Z

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

Karol Wójcik 2021-11-03T05:29:32.036700Z

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

Karol Wójcik 2021-11-03T05:29:47.037300Z

I mean for NAT Gateway.

Karol Wójcik 2021-11-03T05:30:04.037900Z

Why does the Redis is not in the VPC?

steveb8n 2021-11-03T05:30:27.038100Z

Redis only runs in a VPC, not allowed outside

steveb8n 2021-11-03T05:30:44.038600Z

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

steveb8n 2021-11-03T05:31:24.039600Z

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

steveb8n 2021-11-03T05:31:49.040400Z

I don’t think it will cost a lot

Karol Wójcik 2021-11-03T05:31:51.040700Z

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ójcik 2021-11-03T05:32:17.041300Z

It will certainly not cost more

steveb8n 2021-11-03T05:32:20.041500Z

yep, that’s it

steveb8n 2021-11-03T05:32:34.041800Z

HL is a NAT gateway alternative

Karol Wójcik 2021-11-03T05:33:20.043300Z

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

steveb8n 2021-11-03T05:33:31.043800Z

exactly

steveb8n 2021-11-03T05:34:23.044Z

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

steveb8n 2021-11-03T05:34:28.044200Z

but that’s easy to write/test

steveb8n 2021-11-03T05:34:41.044400Z

CDK makes setup easy too

Karol Wójcik 2021-11-03T05:38:44.045700Z

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

steveb8n 2021-11-03T06:50:32.045900Z

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

michaelwhitford 2021-11-02T23:32:22.019800Z

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

Karol Wójcik 2021-11-03T07:14:05.046300Z

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

Karol Wójcik 2021-11-03T07:15:03.046500Z

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ójcik 2021-11-03T07:16:47.046700Z

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

michaelwhitford 2021-11-03T15:55:14.066100Z

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ójcik 2021-11-03T15:58:55.067Z

So initialize jdk.xml.internal at build time.

Karol Wójcik 2021-11-03T15:59:37.068200Z

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

michaelwhitford 2021-11-03T16:01:05.068400Z

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ójcik 2021-11-03T16:01:44.069300Z

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

Karol Wójcik 2021-11-03T16:02:11.070200Z

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

michaelwhitford 2021-11-03T16:02:14.070400Z

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

Karol Wójcik 2021-11-03T16:03:53.070900Z

https://fierycod.github.io/holy-lambda/#/cli

Karol Wójcik 2021-11-03T16:05:01.072Z

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

michaelwhitford 2021-11-03T16:09:43.072300Z

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ójcik 2021-11-03T16:10:28.072800Z

You can do both

Karol Wójcik 2021-11-03T16:10:40.073200Z

Congrats. ;)

Karol Wójcik 2021-11-03T16:11:23.074100Z

You’re very close to getting it working.

michaelwhitford 2021-11-03T16:20:29.074400Z

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)

michaelwhitford 2021-11-03T16:21:03.074600Z

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.

michaelwhitford 2021-11-03T16:22:02.074800Z

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

michaelwhitford 2021-11-03T16:22:30.075Z

I really appreciate the help on troubleshooting this.

Karol Wójcik 2021-11-03T16:23:38.075400Z

Not enough memory

michaelwhitford 2021-11-03T16:25:51.075900Z

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

Karol Wójcik 2021-11-03T16:26:56.076700Z

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

michaelwhitford 2021-11-03T16:27:05.076900Z

Ok

michaelwhitford 2021-11-03T16:32:18.077100Z

Sweet, it compiled!

michaelwhitford 2021-11-03T16:33:34.077300Z

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

michaelwhitford 2021-11-03T16:35:00.077500Z

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

Karol Wójcik 2021-11-03T16:39:05.078Z

You’re very welcome

steveb8n 2021-11-02T23:50:14.020700Z

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

steveb8n 2021-11-02T23:50:43.020900Z

are you calling SSM successfully in native:conf step?

michaelwhitford 2021-11-02T23:58:42.021100Z

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

michaelwhitford 2021-11-02T23:59:46.021300Z

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.

michaelwhitford 2021-11-03T00:02:45.021500Z

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

michaelwhitford 2021-11-03T00:07:16.022200Z

Formatter is crap but that's the whole lambda

steveb8n 2021-11-03T00:58:17.022500Z

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

steveb8n 2021-11-03T00:59:11.023Z

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ójcik 2021-11-03T05:08:53.025200Z

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

Karol Wójcik 2021-11-03T05:14:39.031700Z

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.