nervous-systems / cljs-lambda Goto Github PK
View Code? Open in Web Editor NEWUtilities around deploying Clojurescript functions to AWS Lambda
License: The Unlicense
Utilities around deploying Clojurescript functions to AWS Lambda
License: The Unlicense
This is probably a dumb question, but I've been searching for a solution for a few hours now without luck.
I'm trying to access the S3 API, so that I can manipulate S3 objects from my lambda function and I can't figure out how to do this.
I've tried (def aws (nodejs/require "aws-sdk"))
and (def s3 (nodejs/require "aws-sdk/clients/s3"))
and while they seem to give me something back, I'm unsure what to do with this.
I've tried:
(def S3 (nodejs/require "aws-sdk/clients/s3"))
(def s3-client (new S3))
and this works in the sense that s3-client
is now a non-nil object, but I've been unable to call functions on it.
eg
(.copyObject s3-client #js {:Bucket "bucket" :CopySource "bucket/source-key" :Key "destination-key"})
but it complains that s3-client
does not have a copyObject field.
I then tried to use the cljsjs package for aws-sdk, but still no luck.
I assume this is standard nodejs interop from clojurescript, but this is my first time using nodejs (or lambda) from clojurescript and I can't seem to figure it out. What am I missing?
Any and all help is greatly appreciated!!
When invoking an async promise if Lambda kills the function prior to the async promise being realized on subsequent calls the function is hung and doesn't enter the handler until either a new Lambda zip is uploaded or the Lambda function times out on AWS's infrastructure internally.
Using https://github.com/Type-Zero/promise-timeout-hang you can create two functions promise-hang
and promise-timeout
. When promise-timeout
is invoked, the function will print Starting function
and then throw a timeout error. Subsequent invocations behave the same.
Invoking promise-hang
will print Staring function
and then timeout via the Lambda timeout. Subsequent executions will not run the handler and you will not see Starting function
. Basically at this point the function is useless.
I'm making this issue here because this is the top level where we encountered it but reading around the internet like http://theburningmonk.com/2016/05/aws-lambda-constant-timeout-when-using-bluebird-promise/ it appears that the problem lies in how bluebird is handling async promises.
Any insight is welcome. I'm not quite up to debugging this all the way down.
Should I be able to see the successfully deployed function in AWS console as "work magic"? I can deploy and invoke the function, but I see no trace of it in the console.
Weird issue happened today when I was quickly redeploying lambda functions to production.
lein cljs-lambda deploy
without any other optionsSome of these functions didn't work. Error message was:
{
"errorMessage": "callback called with Error argument, but there was \
a problem while retrieving one or more of its message, name, and stack"
}
I redeployed these functions again with the same command, but one by one. In other words, 13 commands:
lein cljs-lambda deploy FuncName
Problem solved. All functions are working properly.
One issue can be parallelism. Will test tomorrow with :parallel 1
if this is the issue. Also tried to Google it and found: dawson-org/dawson-cli#1 It's worth to investigate it as well.
I've got environment where I can reproduce this issue (tried it, reproduced), will check what's wrong. Either permissions can be wrong in the ZIP file or there's issue when :parallel > 1
.
While reading the README and using mock-context, it looks like that the result is unwrapped and I would have a vector with the values. At least that is what I expect from the comments on the README.
I could fetch the values, but I had to use:
(go
(let [events (<! (cljs.core.async/into [] (testable 5 (mock-context))))]
(println events) ;
))
Found this by accident and it's rather a question, thing for discussion, ...
I've got my custom lambda wrapper, which wraps async-lambda-fn
:
(defn promise-lambda-fn
[creds env event-schema promise-fn & rest]
(async-lambda-fn
(fn [ev context]
(go
(try
(if-let [error (schema/check event-schema ev)]
(fail! context (ex/bad-request error))
(-> (apply promise-fn creds env ev context rest)
(p/then #(succeed! context %))
(p/catch #(fail! context %))))
(catch :default e
(fail! context (ex/internal-server-error "promise-lambda-fn" e))))))))
This wrapper is used in this way:
(def EventSchema
{:principal-id ks/ErebosUserId ...})
(def ^:export handler
(promise-lambda-fn
(credentials)
env-variables
EventSchema
invite-users))
It's a simple wrapper which is auto producing internal server error in case of exception or bad request in case if event is malformed. So far, so good. Works.
By accident, we did send atom value instead of proper message and lambda output is ...
{
"errorMessage": "RequestId: 185a635d-3ffa-11e7-9ee6-33e1af8e69ed Process exited before completing request"
}
... with backtraces like ...
Error: No protocol method IEmptyableCollection.-empty defined for type object: [object Object]
at Object.cljs$core$missing_protocol [as missing_protocol] (/var/task/target/erebos-lambda/cljs/core.cljs:272:4)
... and this happens because of ...
https://github.com/nervous-systems/cljs-lambda/blob/master/cljs-lambda/src/cljs_lambda/util.cljs#L25
... basically, js->clj :keywordize-keys true
can't handle this particular event.
What if I like to return specific response from lambda in this case? Something like our ex/bad-request
(400) instead of this generic error, which produces 500 for example? Event is valid JSON and I personally don't like when 500 is returned instead of 400, just because this can't be parsed / keywordized.
I can live with this, but it's not good if I want to provide better status codes / response to API consumers.
Sample event we did send by accident.
{
"payload": {
"message": {
"state": {
"meta": null,
"cnt": 1,
"root": {
"edit": {},
"bitmap": 512,
"arr": [
{
"ns": null,
"name": "value",
"fqn": "value",
"_hash": 305978217,
"cljs$lang$protocol_mask$partition0$": 2153775105,
"cljs$lang$protocol_mask$partition1$": 4096
},
"foo",
null,
null,
null,
null,
null,
null
]
},
"has_nil_QMARK_": false,
"nil_val": null,
"__hash": null,
"cljs$lang$protocol_mask$partition0$": 16123663,
"cljs$lang$protocol_mask$partition1$": 8196
},
"meta": null,
"validator": null,
"watches": {
"meta": null,
"cnt": 0,
"arr": [],
"__hash": -15128758,
"cljs$lang$protocol_mask$partition0$": 16647951,
"cljs$lang$protocol_mask$partition1$": 8196
},
"cljs$lang$protocol_mask$partition1$": 16386,
"cljs$lang$protocol_mask$partition0$": 6455296
}
}
}
Travis CI did update images today. Didn't find time to investigate this issue yet, maybe something will come to your mind immediately when you see it. There's this error when deploy
is called:
clojure.lang.Compiler$CompilerException: java.lang.ClassNotFoundException: clojure.pprint, compiling:(leiningen/cljs_lambda/aws.clj:181:7)
Will check what's wrong tomorrow.
Hello folks!
It would be really awesome to have something so that we could make cljs-lambda
work in lumo
.
Not only it would have faster startup but also the interactive REPL with lumo
would be super easy to setup (compared to both nRepl and vanilla ClojureScript).
The problem that strikes me immediately is that there is a dependency on core.async
that should be replaced by https://github.com/mfikes/andare. Also promesa
could be replaced by vanilla Bluebird directly.
And....Yes...I see that would drastically change the project layout and it is probably worth a separate project.
In any case, thanks for your work on this, it is quite useful!
& print it to the console
Is there any way I can dynamically change the lambda name (specified in project.clj) to include version/ build number?
The serverless
template (and probably the main cljs-lambda
template as well) is incompatible with the current (1.9.562) version of ClojureScript. Builds fail because java.lang.AssertionError: Assert failed: :nodejs target with :none optimizations requires a :main entry
.
I've tried adding my .core
namespace as the :main
. Bizarrely, that leads to:
Exception in thread "main" java.lang.ClassNotFoundException:
[…]
Caused
by: java.lang.ClassNotFoundException:<project-name>.core
at
java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at
clojure.lang.DynamicClassLoader.findClass(DynamicClassLoader.java:69)
at
java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at
clojure.lang.DynamicClassLoader.loadClass(DynamicClassLoader.java:77)
at
java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at
java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at
clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForName(RT.java:2177)
at
clojure.lang.Compiler.resolveIn(Compiler.java:7145)
at
clojure.lang.Compiler.resolve(Compiler.java:7108)
at
clojure.lang.Compiler.analyzeSymbol(Compiler.java:7069)
at
clojure.lang.Compiler.analyze(Compiler.java:6648)
...
30 more
(where <project-name>
is the name of the project)
It looks like Clojure is trying to find the namespace instead of ClojureScript? I have no idea what's going on at this point.
First of all! Great work! Just deployed my first lambda function!
Not having npm in my path on shell load causes lein cljs-lambda deploy
to silently fail, maybe an error would be great? I just lost half an hour because of this as I didn't expect node to be involved with deploying.
In ClojureScript 1.9.854 a compiler option was added that shims the Node process
object automatically (i.e., it is an opt-out feature). This means that if you are using environment variables in your Lambda functions they will get completely wiped out by the shim. It would be wonderful if the template automatically provided the compiler option with a value of false
going forward.
Would be nice with creating/updating and invocation examples in the README where the aws
cli is used directly. For instance, wrt invokation:
aws lambda invoke \
--invocation-type RequestResponse \
--function-name work-magic \
--region eu-west-1 \
--log-type Tail \
--payload '{"magic-word": "my-lambda-project-token", "spell":"delay-promise"}' \
outfile.txt
When I run lein cljs-lambda invoke work-magic with any arguments it always returns this:
jims-first-cljs-lambda ♘ lein cljs-lambda invoke work-magic
aws lambda invoke /var/folders/41/b5ntx4mn2mv9qk3jyxnsnk_w0000gn/T/lambda-output1140111309954810249.json --function-name work-magic --payload --log-type Tail --query LogResult --output text
java.io.IOException: Cannot run program "aws": error=2, No such file or directory
at java.lang.ProcessBuilder.start (ProcessBuilder.java:1048)
java.lang.Runtime.exec (Runtime.java:620)
clojure.java.shell$sh.invokeStatic (shell.clj:113)
clojure.java.shell$sh.doInvoke (shell.clj:79)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:652)
clojure.core$apply.invoke (core.clj:641)
leiningen.cljs_lambda.aws$aws_cli_BANG_.invokeStatic (aws.clj:72)
leiningen.cljs_lambda.aws$aws_cli_BANG_.doInvoke (aws.clj:69)
clojure.lang.RestFn.invoke (RestFn.java:445)
clojure.core$partial$fn__4759.invoke (core.clj:2516)
leiningen.cljs_lambda.aws$invoke_BANG_.invokeStatic (aws.clj:247)
leiningen.cljs_lambda.aws$invoke_BANG_.invoke (aws.clj:235)
leiningen.cljs_lambda$invoke.invokeStatic (cljs_lambda.clj:188)
leiningen.cljs_lambda$invoke.invoke (cljs_lambda.clj:184)
leiningen.cljs_lambda$cljs_lambda.invokeStatic (cljs_lambda.clj:230)
leiningen.cljs_lambda$cljs_lambda.doInvoke (cljs_lambda.clj:214)
clojure.lang.RestFn.invoke (RestFn.java:442)
clojure.lang.Var.invoke (Var.java:388)
clojure.lang.AFn.applyToHelper (AFn.java:160)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invokeStatic (core.clj:648)
clojure.core$apply.invoke (core.clj:641)
leiningen.core.main$partial_task$fn__5932.doInvoke (main.clj:272)
clojure.lang.RestFn.applyTo (RestFn.java:139)
clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:648)
clojure.core$apply.invoke (core.clj:641)
leiningen.core.main$apply_task.invokeStatic (main.clj:322)
leiningen.core.main$apply_task.invoke (main.clj:308)
leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:328)
leiningen.core.main$resolve_and_apply.invoke (main.clj:324)
leiningen.core.main$_main$fn__5998.invoke (main.clj:401)
leiningen.core.main$_main.invokeStatic (main.clj:394)
leiningen.core.main$_main.doInvoke (main.clj:391)
clojure.lang.RestFn.invoke (RestFn.java:436)
clojure.lang.Var.invoke (Var.java:388)
clojure.lang.AFn.applyToHelper (AFn.java:160)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invokeStatic (core.clj:646)
clojure.main$main_opt.invokeStatic (main.clj:314)
clojure.main$main_opt.invoke (main.clj:310)
clojure.main$main.invokeStatic (main.clj:421)
clojure.main$main.doInvoke (main.clj:384)
clojure.lang.RestFn.invoke (RestFn.java:482)
clojure.lang.Var.invoke (Var.java:401)
clojure.lang.AFn.applyToHelper (AFn.java:171)
clojure.lang.Var.applyTo (Var.java:700)
clojure.main.main (main.java:37)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec (UNIXProcess.java:-2)
java.lang.UNIXProcess.<init> (UNIXProcess.java:247)
java.lang.ProcessImpl.start (ProcessImpl.java:134)
java.lang.ProcessBuilder.start (ProcessBuilder.java:1029)
java.lang.Runtime.exec (Runtime.java:620)
clojure.java.shell$sh.invokeStatic (shell.clj:113)
clojure.java.shell$sh.doInvoke (shell.clj:79)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:652)
clojure.core$apply.invoke (core.clj:641)
leiningen.cljs_lambda.aws$aws_cli_BANG_.invokeStatic (aws.clj:72)
leiningen.cljs_lambda.aws$aws_cli_BANG_.doInvoke (aws.clj:69)
clojure.lang.RestFn.invoke (RestFn.java:445)
clojure.core$partial$fn__4759.invoke (core.clj:2516)
leiningen.cljs_lambda.aws$invoke_BANG_.invokeStatic (aws.clj:247)
leiningen.cljs_lambda.aws$invoke_BANG_.invoke (aws.clj:235)
leiningen.cljs_lambda$invoke.invokeStatic (cljs_lambda.clj:188)
leiningen.cljs_lambda$invoke.invoke (cljs_lambda.clj:184)
leiningen.cljs_lambda$cljs_lambda.invokeStatic (cljs_lambda.clj:230)
leiningen.cljs_lambda$cljs_lambda.doInvoke (cljs_lambda.clj:214)
clojure.lang.RestFn.invoke (RestFn.java:442)
clojure.lang.Var.invoke (Var.java:388)
clojure.lang.AFn.applyToHelper (AFn.java:160)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invokeStatic (core.clj:648)
clojure.core$apply.invoke (core.clj:641)
leiningen.core.main$partial_task$fn__5932.doInvoke (main.clj:272)
clojure.lang.RestFn.applyTo (RestFn.java:139)
clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:648)
clojure.core$apply.invoke (core.clj:641)
leiningen.core.main$apply_task.invokeStatic (main.clj:322)
leiningen.core.main$apply_task.invoke (main.clj:308)
leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:328)
leiningen.core.main$resolve_and_apply.invoke (main.clj:324)
leiningen.core.main$_main$fn__5998.invoke (main.clj:401)
leiningen.core.main$_main.invokeStatic (main.clj:394)
leiningen.core.main$_main.doInvoke (main.clj:391)
clojure.lang.RestFn.invoke (RestFn.java:436)
clojure.lang.Var.invoke (Var.java:388)
clojure.lang.AFn.applyToHelper (AFn.java:160)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invokeStatic (core.clj:646)
clojure.main$main_opt.invokeStatic (main.clj:314)
clojure.main$main_opt.invoke (main.clj:310)
clojure.main$main.invokeStatic (main.clj:421)
clojure.main$main.doInvoke (main.clj:384)
clojure.lang.RestFn.invoke (RestFn.java:482)
clojure.lang.Var.invoke (Var.java:401)
clojure.lang.AFn.applyToHelper (AFn.java:171)
clojure.lang.Var.applyTo (Var.java:700)
clojure.main.main (main.java:37)
I am running on mac 10.11.6 with Leiningen 2.7.1 on Java 1.8.0_121 Java HotSpot(TM) 64-Bit Server VM
Hey, thanks again for making this. I'm wordering how to return normal JSON as my response seems to always look like a Clojure map even when I return (js-obj "a" 1 "b" true "c" "hello there, caller!")
or #js{:a 1, :b true, :c nil}
.
I know the horse is already out of the stable but at least let this be the note on the door after the fact...
When the code db6a26e was updated to use callback. This had some unforeseen consequences that could severely affect the function of Lambda programs. In our case, we are using pg-pool for SQL connections. We were boggled when we were writing a new library that used the same sql calls seemed to wait until the idleTimeoutMillis hit (30 seconds in our case). The lambda code (sprinkled with tons of prn) gave us confidence that that part of the code was executing fine, including the sql query. However, downgrading cljs-lambda to 0.3.3 from 0.3.6 made the problem go away, because it doesn't wait for unfulfilled promises anymore.
I'm raising the issue because even as I directly asked for the update, I didn't realize it until we lost a morning on troubleshooting. Clearly the unfulfilled promises bug in our code needs to be fixed (I think it has to do with the pg-pool of connections) That being said, a bump in the bug fix number of the project version doesn't necessary convey how big the change really was. It was a "change the way all lambda by default respond to AWS" change.
No message is shown, which is not optimal. Some kind of info message would be nice.
Hi,
lein cljs-lamdba deploy failed on Ubuntu 14.04. Could you help me what is the problem?
~/mylambda/my-lambda-project# sudo lein cljs-lambda deploy
WARNING: You're currently running as root; probably by accident.
Press control-C to abort or Enter to continue as root.
Set LEIN_ROOT to disable this warning.
Compiling "target/my-lambda-project/my_lambda_project.js" from ["src"]...
Compiling "target/my-lambda-project/my_lambda_project.js" failed.
clojure.lang.ExceptionInfo: failed compiling file:target/my-lambda-project/cljs_lambda/macros.cljc {:file #object[java.io.File 0x6c2658b "target/my-lambda-project/cljs_lambda/macros.cljc"]}
at clojure.core$ex_info.invokeStatic(core.clj:4617)
at clojure.core$ex_info.invoke(core.clj:4617)
at cljs.compiler$compile_file$fn__3406.invoke(compiler.cljc:1372)
at cljs.compiler$compile_file.invokeStatic(compiler.cljc:1338)
at cljs.compiler$compile_file.invoke(compiler.cljc:1318)
at cljs.closure$compile_file.invokeStatic(closure.clj:473)
at cljs.closure$compile_file.invoke(closure.clj:464)
at cljs.closure$eval5143$fn__5144.invoke(closure.clj:540)
at cljs.closure$eval5079$fn__5080$G__5068__5087.invoke(closure.clj:430)
at cljs.closure$compile_from_jar.invokeStatic(closure.clj:522)
at cljs.closure$compile_from_jar.invoke(closure.clj:510)
at cljs.closure$eval5149$fn__5150.invoke(closure.clj:550)
at cljs.closure$eval5079$fn__5080$G__5068__5087.invoke(closure.clj:430)
at cljs.closure$compile_sources$iter__5264__5268$fn__5269.invoke(closure.clj:869)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:688)
at clojure.core$next__4341.invokeStatic(core.clj:64)
at clojure.core$dorun.invokeStatic(core.clj:3033)
at clojure.core$doall.invokeStatic(core.clj:3039)
at clojure.core$doall.invoke(core.clj:3039)
at cljs.closure$compile_sources.invokeStatic(closure.clj:865)
at cljs.closure$compile_sources.invoke(closure.clj:854)
at cljs.closure$build.invokeStatic(closure.clj:1943)
at cljs.closure$build.invoke(closure.clj:1882)
at cljs.build.api$build.invokeStatic(api.clj:210)
at cljs.build.api$build.invoke(api.clj:198)
at cljs.build.api$build.invokeStatic(api.clj:201)
at cljs.build.api$build.invoke(api.clj:198)
at cljsbuild.compiler$compile_cljs$fn__5771.invoke(compiler.clj:60)
at cljsbuild.compiler$compile_cljs.invokeStatic(compiler.clj:59)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:48)
at cljsbuild.compiler$run_compiler.invokeStatic(compiler.clj:168)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:122)
at user$eval5908$iter__5944__5948$fn__5949$fn__5967.invoke(form-init46941676171948885.clj:1)
at user$eval5908$iter__5944__5948$fn__5949.invoke(form-init46941676171948885.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:521)
at clojure.core$seq__4357.invokeStatic(core.clj:137)
at clojure.core$dorun.invokeStatic(core.clj:3024)
at clojure.core$doall.invokeStatic(core.clj:3039)
at clojure.core$doall.invoke(core.clj:3039)
at user$eval5908.invokeStatic(form-init46941676171948885.clj:1)
at user$eval5908.invoke(form-init46941676171948885.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6917)
at clojure.lang.Compiler.load(Compiler.java:7379)
at clojure.lang.Compiler.loadFile(Compiler.java:7317)
at clojure.main$load_script.invokeStatic(main.clj:275)
at clojure.main$init_opt.invokeStatic(main.clj:277)
at clojure.main$init_opt.invoke(main.clj:277)
at clojure.main$initialize.invokeStatic(main.clj:308)
at clojure.main$null_opt.invokeStatic(main.clj:342)
at clojure.main$null_opt.invoke(main.clj:339)
at clojure.main$main.invokeStatic(main.clj:421)
at clojure.main$main.doInvoke(main.clj:384)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: clojure.lang.ExceptionInfo: java.lang.ClassNotFoundException: java.util.concurrent.CompletableFuture, compiling:(promesa/impl/promise.cljc:1:1) in file target/my-lambda-project/cljs_lambda/macros.cljc {:tag :cljs/analysis-error}
at clojure.core$ex_info.invokeStatic(core.clj:4617)
at clojure.core$ex_info.invoke(core.clj:4617)
at cljs.analyzer$error.invokeStatic(analyzer.cljc:580)
at cljs.analyzer$error.invoke(analyzer.cljc:576)
at cljs.analyzer$analyze.invokeStatic(analyzer.cljc:2616)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2605)
at cljs.compiler$emit_source.invokeStatic(compiler.cljc:1239)
at cljs.compiler$emit_source.invoke(compiler.cljc:1219)
at cljs.compiler$compile_file_STAR_$fn__3383.invoke(compiler.cljc:1290)
at cljs.compiler$with_core_cljs.invokeStatic(compiler.cljc:1154)
at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1145)
at cljs.compiler$compile_file_STAR_.invokeStatic(compiler.cljc:1279)
at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc:1275)
at cljs.compiler$compile_file$fn__3406.invoke(compiler.cljc:1360)
... 60 more
Caused by: java.lang.ClassNotFoundException: java.util.concurrent.CompletableFuture, compiling:(promesa/impl/promise.cljc:1:1)
at clojure.lang.Compiler.load(Compiler.java:7391)
at clojure.lang.RT.loadResourceScript(RT.java:372)
at clojure.lang.RT.loadResourceScript(RT.java:363)
at clojure.lang.RT.load(RT.java:453)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at promesa.core$eval8798$loading__5569__auto____8799.invoke(core.cljc:25)
at promesa.core$eval8798.invokeStatic(core.cljc:25)
at promesa.core$eval8798.invoke(core.cljc:25)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6916)
at clojure.lang.Compiler.load(Compiler.java:7379)
at clojure.lang.RT.loadResourceScript(RT.java:372)
at clojure.lang.RT.loadResourceScript(RT.java:363)
at clojure.lang.RT.load(RT.java:453)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at cljs_lambda.macros$eval8792$loading__5569__auto____8793.invoke(macros.cljc:1)
at cljs_lambda.macros$eval8792.invokeStatic(macros.cljc:1)
at cljs_lambda.macros$eval8792.invoke(macros.cljc:1)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6916)
at clojure.lang.Compiler.load(Compiler.java:7379)
at clojure.lang.RT.loadResourceScript(RT.java:372)
at clojure.lang.RT.loadResourceScript(RT.java:363)
at clojure.lang.RT.load(RT.java:453)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at cljs.analyzer$ns_side_effects$fn__2118.invoke(analyzer.cljc:2541)
at cljs.analyzer$ns_side_effects.invokeStatic(analyzer.cljc:2540)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:2513)
at cljs.analyzer$analyze_STAR_$fn__2154.invoke(analyzer.cljc:2603)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:341)
at clojure.core$reduce.invokeStatic(core.clj:6544)
at clojure.core$reduce.invoke(core.clj:6527)
at cljs.analyzer$analyze_STAR_.invokeStatic(analyzer.cljc:2603)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2593)
at cljs.analyzer$analyze.invokeStatic(analyzer.cljc:2618)
... 69 more
Caused by: java.lang.ClassNotFoundException: java.util.concurrent.CompletableFuture
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at clojure.lang.DynamicClassLoader.findClass(DynamicClassLoader.java:69)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at clojure.lang.DynamicClassLoader.loadClass(DynamicClassLoader.java:77)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:278)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForNameNonLoading(RT.java:2181)
at promesa.impl.promise$eval8804$loading__5569__auto____8805.invoke(promise.cljc:25)
at promesa.impl.promise$eval8804.invokeStatic(promise.cljc:25)
at promesa.impl.promise$eval8804.invoke(promise.cljc:25)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6916)
at clojure.lang.Compiler.load(Compiler.java:7379)
... 157 more
Subprocess failed
Consider following scenario:
Upon build & deploy, one ZIP file is created for all lambda functions and this file is uploaded for every lambda function. This takes space and has performance implications when lambda is cold and it also needs slightly more memory.
What's your recommended approach / best practice to cope with this? Are you splitting lambda functions into groups and one project per group? Or project per lambda? Or did I miss something and I shouldn't worry? Can't get out of my head that I would like to process my lambda functions with :advanced
optimization per lambda, so, there will be specific and small ZIP file per lambda function, but I don't like one lambda function = one project approach.
My ZIP file is 0.5MB now.
I added transit as an optional format to send and/or receive data. Is this something you have plans to support? Would you mind if I created a pull request for it?
Documentation here.
Example:
:cljs-lambda {
:defaults {:env {:table-name "abc"}}
:functions [{
:name "abc"
:invoke "def"
:env {:extra-stuff "xyz"}}]}
:defaults
contains env variables for all functions. :env
inside :functions
list is merged with environment variables from :defaults
.
Docs quote: environment variables must start with a-zA-Z
and can contain a-ZA-Z0-9_
.
We will transform keywords in this way:
We will not check these variables and we will let aws
cli to fail if they do not meet requirements.
We need to add this to:
Update function is little bit harder, because we have to get function configuration (if it exists) and compare it. We can do it in the same way as we did in #48.
Sounds good?
There's no way how to configure VPC for lambda function. We do use it heavily now and we have to do it manually.
There's --vpc-config
in AWS CLI for lambda create-function
and lambda update-function-configuration
. Documentation says:
--vpc-config (structure) If your Lambda function accesses resources in a VPC, you provide this parameter identifying the list of security group IDs and subnet IDs. These must belong to the same VPC. You must provide at least one security group and one subnet ID. Shorthand Syntax: SubnetIds=string,string,SecurityGroupIds=string,string
So, my proposal is to add :vpc-config
which will accept shorthand syntax. So, Lambda configuration can look like:
{:name ...
:invoke ...
:role ...
:vpc-config "SubnetIds=a,b,SecurityGroupIds=d,e"}
Or we can split it to :vpc-subnet-ids
and :vpc-security-group-ids
. Depends.
The first one is easier to maintain in case AWS CLI will be changed in the future. Which one do you like more? I'll create pull request, just want to discuss it before I really do it.
Not sure why. Using open JDK8 on Arch Linux.
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
$ lein version
Leiningen 2.5.1 on Java 1.8.0_45 Java HotSpot(TM) 64-Bit Server VM
Compiling ClojureScript.
Writing index to /home/me/project/cljs/lambda-ami-lookup/out/index.js
Adding files from /home/me/project/cljs/lambda-ami-lookup/out
Adding files from /home/me/project/cljs/lambda-ami-lookup/node_modules
Writing zip to /home/me/project/cljs/lambda-ami-lookup/out/lambda-ami-lookup.zip
Registering handler index.lambda_ami_lookup_core_work_magic for function work-magic
aws lambda get-function --function-name work-magic
aws lambda create-function --function-name work-magic --zip-file fileb:////home/me/project/clme nodejs --handler index.lambda_ami_lookup_core_work_magic --role lambda-iam-AMILookupRole-16JFOYHF
Error parsing parameter '--zip-file': Unable to load paramfile fileb:///home/me/project/cljs] No such file or directory: '/home/me/project/cljs/lambda-ami-lookup/out/lambda-ami-lookup.
I wish I could give you more :(
I haven't used the Serverless framework before, but my understanding is that one of it's biggest selling points is abstracting away the differences between GCP Functions, Azure Cloud Functions and AWS Lambda, making it possible to run almost the same codebase across different providers. Does that apply to projects made with this template too? Am I misunderstanding what Serverless provides, or what portions of it this project uses? (Is it just for uploading to AWS Lambda?)
& aliases, I guess.
I'm working on a function that will depend on a node.js package. Guided by the comment here:
Note: Under Node.js there is little reason to use advanced optimizations. While advanced optimizations does apply performance related optimizations, these are now largely obviated by optimizations present in modern JavaScript virtual machines like V8, SpiderMonkey, and JavaScriptCore. For Node.js, :simple or :none optimizations suffice and using them removes the need for extra steps like supplying an externs file.
I decided to try deploying the cljs-lambda example function using :simple
optiimizations. But the deployed function fails. (It took me a while to figure out the nature of the failure, but base.js
is apparently attempting to load a non-existent deps.js
file.)
Would it be possible to configure lambda functions using metadata instead of listing it in the project.clj? Something like this:
(defn ^:export ^:aws-lambda sample [env context]
"YAY")
Something like this in the none/simple templates:
{{#module}}
{{#function}}
exports.{{export}} = function(event, ctx, cb) {
goog.require("{{name}}");
{{js-name}}(event, ctx, cb);
}
{{/function}}
{{/module}}
Here's a better description of the ReferenceError bug I tried to fix as part of #77.
To reproduce the bug, create a new project with the serverless-cljs template, then change :optimizations to :advanced and finally try to run the output: you get the ReferenceError.
The serverless-cljs template creates the following project.clj:
(defproject bar "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.8.51"]
[io.nervous/cljs-lambda "0.3.5"]]
:plugins [[lein-npm "0.6.2"]
[io.nervous/lein-cljs-lambda "0.6.5"]]
:npm {:dependencies [[serverless-cljs-plugin "0.1.2"]]}
:cljs-lambda {:compiler
{:inputs ["src"]
:options {:output-to "target/bar/bar.js"
:output-dir "target/bar"
:target :nodejs
:language-in :ecmascript5
:optimizations :advanced}}})
As you can see it uses :cljs-lambda {:compiler ...} to configure the compiler instead of specifying a :cljsbuild key. That leads lein-cljs-lambda to invoking the clojurescript compiler directly instead of going through cljsbuild, which ultimately causes this issue.
Below is a transcript of how I can reproduce the bug:
Script started on Wed May 3 20:05:34 2017
alessandro@june:/tmp$ lein new serverless-cljs bar
Generating fresh 'lein new' serverless-cljs project.
alessandro@june:/tmp$ cd b�ar/
alessandro@june:/tmp/bar$ sed -i -e s/:none/:advanced/ project.clj
alessandro@june:/tmp/bar$ grep optimizations project.clj
:optimizations :advanced}}})
alessandro@june:/tmp/bar$ lein deps
[email protected] /private/tmp/bar
└─┬ [email protected]
├── [email protected]
├── [email protected]
└─┬ [email protected]
└── [email protected]
alessandro@june:/tmp/bar$ serverless package
Serverless: Targeting /private/tmp/bar/.serverless/bar.zip
Serverless: Packaging service...
Serverless: Executing "lein update-in :cljs-lambda assoc :functions '[{:name "bar-dev-echo" :invoke bar.core/echo}]' -- cljs-lambda build :output /private/tmp/bar/.serverless/bar.zip :quiet"
Serverless: Returning artifact path /private/tmp/bar/.serverless/bar.zip�[39m
alessandro@june:/tmp/bar$ unzip -q -d aws_zip .serverless/bar.zip
alessandro@june:/tmp/bar$ cd aws_zip
alessandro@june:/tmp/bar/aws_zip$ cat index.js
require("./target/bar/bar.js");
exports.bar_core_SLASH_echo = bar.core.echo;
alessandro@june:/tmp/bar/aws_zip$ node index.js
/private/tmp/bar/aws_zip/index.js:4
exports.bar_core_SLASH_echo = bar.core.echo;
^
ReferenceError: bar is not defined
at Object.<anonymous> (/private/tmp/bar/aws_zip/index.js:4:31)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:423:7)
at startup (bootstrap_node.js:147:9)
at bootstrap_node.js:538:3
alessandro@june:/tmp/bar/aws_zip$ exit
exit
Script done on Wed May 3 20:08:35 2017
Hello,
I'm trying to make a lambda endpoint that sends messages to SNS...
(ns parsehook.core
(:require [cljs-lambda.util :refer [async-lambda-fn]]
[fink-nottle.sns :as sns]
[cljs.core.async :refer [chan <!]]
[eulalie.instance-data :refer [default-iam-credentials!]])
(:require-macros [cljs.core.async.macros :refer [go]]))
(def ^:export work-magic
(async-lambda-fn
(fn [event context]
(go
(<! (sns/publish-topic!
(<! (default-iam-credentials!))
"arn:aws:sns:us-west-2:785400771354:parsehook-qa"
(.stringify js/JSON event)))))))
does the above usage of default-iam-credentials look correct? When I do it this way and invoke the function I get:
{:errorMessage "Task timed out after 3.00 seconds"}
When i pass creds as a regular map with {:access-key, :secret-key and :region} it works. But I'd prefer to use the IAM role if possible. Not sure if my script is throwing an exception when I try to use (default-iam-credentials!)... I'm unclear how error reporting works in Lambda, beyond returning an Error via the channel.
I am not in the default region, not sure if I need to assoc region into the default-iam-credential or something. I'm totally new to lambda, just trying to figure it out. Thanks!
Our projects heavily rely on :cljs-lambda :defaults :env
. Also, we have production variables set in the :production
profile (profiles.clj). Sometimes we forget to ...
#=(eval (System/getenv "STRIPE_API_KEY_SECRET"))
) and dev value is deployed to production,Repetitive tasks, prone to error, ... Boring, no one wants to do them.
My idea is to enhance cljs-lambda plugin with some validation task. Something like:
Do you think it's good enhancement for cljs-lambda plugin or we should create new plugin? Honestly, not sure if I can come up with generic validator, with enough parameters, to suit needs for lot of people. Our cases are described above, but there can be lot of other cases. Also not sure if plugin can read all these combinations from project & profile files without merging, etc. Didn't test it yet, just thinking aloud.
They're there, on Node, so whatever
Running the commands in the readme, I get the following error trying to invoke the Lambda function. I'm not 100% on the issue, but I suspect it could be that the payload doesn't have single quoted stings around it?
$lein cljs-lambda invoke work-magic '{"variety": "black"}'
aws lambda invoke /var/folders/5s/0stnfr1s5tjdvcjfy_xdkdb00000gn/T/lambda-output4490944749712244058.json --function-name work-magic --payload {"variety": "black"} --log-type Tail --query LogResult
java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.lang.String
at base64_clj.core$decode.invoke (core.clj:125)
base64_clj.core$decode.invoke (core.clj:123)
leiningen.cljs_lambda.aws$invoke_BANG_.invoke (aws.clj:98)
leiningen.cljs_lambda$invoke.doInvoke (cljs_lambda.clj:93)
clojure.lang.RestFn.applyTo (RestFn.java:142)
clojure.core$apply.invoke (core.clj:632)
leiningen.cljs_lambda$cljs_lambda.doInvoke (cljs_lambda.clj:121)
clojure.lang.RestFn.invoke (RestFn.java:464)
clojure.lang.Var.invoke (Var.java:394)
clojure.lang.AFn.applyToHelper (AFn.java:165)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invoke (core.clj:632)
leiningen.core.main$partial_task$fn__6030.doInvoke (main.clj:261)
clojure.lang.RestFn.applyTo (RestFn.java:139)
clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invoke (core.clj:632)
leiningen.core.main$apply_task.invoke (main.clj:311)
leiningen.core.main$resolve_and_apply.invoke (main.clj:317)
leiningen.core.main$_main$fn__6096.invoke (main.clj:390)
leiningen.core.main$_main.doInvoke (main.clj:383)
clojure.lang.RestFn.invoke (RestFn.java:457)
clojure.lang.Var.invoke (Var.java:394)
clojure.lang.AFn.applyToHelper (AFn.java:165)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invoke (core.clj:630)
clojure.main$main_opt.invoke (main.clj:316)
clojure.main$main.doInvoke (main.clj:421)
clojure.lang.RestFn.invoke (RestFn.java:512)
clojure.lang.Var.invoke (Var.java:409)
clojure.lang.AFn.applyToHelper (AFn.java:178)
clojure.lang.Var.applyTo (Var.java:700)
clojure.main.main (main.java:37)
I was stoked to see this already existed. I have a couple of questions regarding implementation however, that to me were not entierly clear from the readme or blog posts. I would like to test the lambda function locally before deploying it. I got it working with basic examples in the tests. But when I started using callbacks (of external node-libs) in the lambda function the test finished before the callback came back, (Naturally, since the function returned while the callback was still firing).
Any details on when to use lambda/succeed!
vs returning go channels, I understood that async-lambda-fn
was supposed to be better than wrap-lambda-fn
, but did not understand how?
Ultimately, any tips on how would I set up a good REPL-workflow with this?
I've tried :region
in [:cljs-lambda :defaults]
, and in [:cljs-lambda]
and they both don't seem to be using the supplied region, and are instead taking the one from my profile. Should I be putting it somewhere else?
It's a pain to :publish & :alias lot of functions (same for all of them, like build-XX where XX is Travis build number for example) without additional scripting. Is anyone working on this? If not, I need it and I would like to help with this feature if you're interested.
Apologies if this is obvious, but I can't get doo to work with the Serverless project file. I see that the template is different. Should I not use doo with Serverless? Or is there some way of doing it that I don't understand? If the former, please advise on testing strategies. Thanks!
Hi, would it be possible to add possibility to skip npm install
step (https://github.com/nervous-systems/cljs-lambda/blob/master/plugin/src/leiningen/cljs_lambda.clj#L123)? The reason is that I want to use yarn instead of npm. What do you think?
While using this in ClojureScript:
(:require [cljs-lambda.util :refer [mock-context]])
I can use mock-context and it is #<function cljs_lambda$util$mock_context(){...
While on a ClojureScript REPL, using the same require, mock-context is always nil. I have tried both Rhino and Node.js REPLs. I can import and use async-lambda-fn, for instance, but not mock-context.
Simple that require line above followed by (mock-context)
will raise an error, because mock-context is nil.
Hi, I'm trying to create a lambda using this cljs-lambda and https://github.com/r0man/sqlingvo.node in order to communicate with an postgres RDS db. I'm hitting a few problems which I think are related to advanced optimizations. I've tried to set the optimzation to none but I can't get a working lambda. I'm getting errors like 'Unable to import module 'index'. Are there any examples of cljs-lambda packages without advanced optimizations so I can compare to my project and rule this out?
From the AWS docs:
If you previously created Lambda functions using Node.js runtime v0.10.42, you used one of the context object methods (done(), succeed(), and fail()) to terminate your Lambda function. In Node.js runtime v4.3, these methods are supported primarily for backward compatibility. We recommend you use the callback (see Using the Callback Parameter).
There's more on their reasoning in the announcement.
I have set up the aws cli and configured the user role. However, when I invoke the function it always returns ":errorMessage "Your magic word is garbage""
I run lein cljs-lambda invoke work-magic '{"spell": "delay-promise", "msecs": 500, "magic-word": "my-lambda-project-token"}'
output:
aws lambda invoke /var/folders/41/b5ntx4mn2mv9qk3jyxnsnk_w0000gn/T/lambda-output7320674589193443835.json --function-name work-magic --payload {"spell": "delay-promise", "msecs": 500, "magic-word": "my-lambda-project-token"} --log-type Tail --query LogResult --output text
START RequestId: e92005f3-b9f7-11e7-9c52-0d9eab9ceec1 Version: $LATEST
2017-10-26T02:46:49.182Z e92005f3-b9f7-11e7-9c52-0d9eab9ceec1 {"errorMessage":"Your magic word is garbage","errorType":"Error","stackTrace":["Function. (/var/task/target/mylambylam/mylambylam/core.cljs:41:12)","Function.cljs.core.apply.cljs$core$IFn$_invoke$arity$2 (/var/task/target/mylambylam/cljs/core.cljs:3566:18)","cljs$core$apply (/var/task/target/mylambylam/cljs/core.cljs:3557:1)","/var/task/target/mylambylam/cljs_lambda/util.cljs:40:24","promesa.impl.proto._promise.function (/var/task/target/mylambylam/promesa/impl/promise.cljc:199:8)","promesa$impl$proto$_promise (/var/task/target/mylambylam/promesa/impl/proto.cljc:41:1)","promesa$core$promise (/var/task/target/mylambylam/promesa/core.cljc:71:4)","Function.cljs_lambda.util.invoke_async.cljs$core$IFn$_invoke$arity$variadic (/var/task/target/mylambylam/cljs_lambda/util.cljs:36:4)","cljs_lambda$util$invoke_async (/var/task/target/mylambylam/cljs_lambda/util.cljs:35:1)","/var/task/target/mylambylam/cljs_lambda/util.cljs:110:15","cljs_lambda.util.wrap_lambda_fn.G__12212__delegate (/var/task/target/mylambylam/cljs_lambda/util.cljs:25:6)","cljs_lambda.util.wrap_lambda_fn.G__12212 (/var/task/target/mylambylam/cljs_lambda/util.cljs:20:3)","invoke (/var/runtime/node_modules/awslambda/index.js:288:5)","InvokeManager.start (/var/runtime/node_modules/awslambda/index.js:150:9)","Object. (/var/runtime/node_modules/awslambda/index.js:482:52)"]}
END RequestId: e92005f3-b9f7-11e7-9c52-0d9eab9ceec1
REPORT RequestId: e92005f3-b9f7-11e7-9c52-0d9eab9ceec1 Duration: 390.49 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 71 MB
{:errorMessage "Your magic word is garbage",
:errorType "Error",
:stackTrace
["Function. (/var/task/target/mylambylam/mylambylam/core.cljs:41:12)"
"Function.cljs.core.apply.cljs$core$IFn$_invoke$arity$2 (/var/task/target/mylambylam/cljs/core.cljs:3566:18)"
"cljs$core$apply (/var/task/target/mylambylam/cljs/core.cljs:3557:1)"
"/var/task/target/mylambylam/cljs_lambda/util.cljs:40:24"
"promesa.impl.proto._promise.function (/var/task/target/mylambylam/promesa/impl/promise.cljc:199:8)"
"promesa$impl$proto$_promise (/var/task/target/mylambylam/promesa/impl/proto.cljc:41:1)"
"promesa$core$promise (/var/task/target/mylambylam/promesa/core.cljc:71:4)"
"Function.cljs_lambda.util.invoke_async.cljs$core$IFn$_invoke$arity$variadic (/var/task/target/mylambylam/cljs_lambda/util.cljs:36:4)"
"cljs_lambda$util$invoke_async (/var/task/target/mylambylam/cljs_lambda/util.cljs:35:1)"
"/var/task/target/mylambylam/cljs_lambda/util.cljs:110:15"
"cljs_lambda.util.wrap_lambda_fn.G__12212__delegate (/var/task/target/mylambylam/cljs_lambda/util.cljs:25:6)"
"cljs_lambda.util.wrap_lambda_fn.G__12212 (/var/task/target/mylambylam/cljs_lambda/util.cljs:20:3)"
"invoke (/var/runtime/node_modules/awslambda/index.js:288:5)"
"InvokeManager.start (/var/runtime/node_modules/awslambda/index.js:150:9)"
"Object. (/var/runtime/node_modules/awslambda/index.js:482:52)"]}
When I run the lein cljs-commands it seems to work, but I get this error in the console:
java.util.concurrent.ExecutionException: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('V' (code 86)): Expected space separating root-level values
at [Source: java.io.StringReader@174e1b69; line: 1, column: 3]
at java.util.concurrent.FutureTask.report (FutureTask.java:122)
java.util.concurrent.FutureTask.get (FutureTask.java:192)
sun.reflect.NativeMethodAccessorImpl.invoke0 (NativeMethodAccessorImpl.java:-2)
sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke (Method.java:498)
clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:93)
clojure.lang.Reflector.invokeNoArgInstanceMember (Reflector.java:313)
leiningen.cljs_lambda.aws$do_functions_BANG_.invokeStatic (aws.clj:208)
leiningen.cljs_lambda.aws$do_functions_BANG_.invoke (aws.clj:197)
leiningen.cljs_lambda.aws$deploy_BANG_.invokeStatic (aws.clj:211)
leiningen.cljs_lambda.aws$deploy_BANG_.invoke (aws.clj:210)
leiningen.cljs_lambda$deploy.invokeStatic (cljs_lambda.clj:177)
leiningen.cljs_lambda$deploy.invoke (cljs_lambda.clj:172)
leiningen.cljs_lambda$cljs_lambda.invokeStatic (cljs_lambda.clj:230)
leiningen.cljs_lambda$cljs_lambda.doInvoke (cljs_lambda.clj:214)
clojure.lang.RestFn.invoke (RestFn.java:425)
clojure.lang.Var.invoke (Var.java:383)
clojure.lang.AFn.applyToHelper (AFn.java:156)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invokeStatic (core.clj:648)
clojure.core$apply.invoke (core.clj:641)
leiningen.core.main$partial_task$fn__5932.doInvoke (main.clj:272)
clojure.lang.RestFn.applyTo (RestFn.java:139)
clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:648)
clojure.core$apply.invoke (core.clj:641)
leiningen.core.main$apply_task.invokeStatic (main.clj:322)
leiningen.core.main$apply_task.invoke (main.clj:308)
leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:328)
leiningen.core.main$resolve_and_apply.invoke (main.clj:324)
leiningen.core.main$_main$fn__5998.invoke (main.clj:401)
leiningen.core.main$_main.invokeStatic (main.clj:394)
leiningen.core.main$_main.doInvoke (main.clj:391)
clojure.lang.RestFn.invoke (RestFn.java:421)
clojure.lang.Var.invoke (Var.java:383)
clojure.lang.AFn.applyToHelper (AFn.java:156)
clojure.lang.Var.applyTo (Var.java:700)
clojure.core$apply.invokeStatic (core.clj:646)
clojure.main$main_opt.invokeStatic (main.clj:314)
clojure.main$main_opt.invoke (main.clj:310)
clojure.main$main.invokeStatic (main.clj:421)
clojure.main$main.doInvoke (main.clj:384)
clojure.lang.RestFn.invoke (RestFn.java:457)
clojure.lang.Var.invoke (Var.java:394)
clojure.lang.AFn.applyToHelper (AFn.java:165)
clojure.lang.Var.applyTo (Var.java:700)
clojure.main.main (main.java:37)
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('V' (code 86)): Expected space separating root-level values
at [Source: java.io.StringReader@174e1b69; line: 1, column: 3]
at com.fasterxml.jackson.core.JsonParser._constructError (JsonParser.java:1487)
com.fasterxml.jackson.core.base.ParserMinimalBase._reportError (ParserMinimalBase.java:518)
com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar (ParserMinimalBase.java:447)
com.fasterxml.jackson.core.base.ParserMinimalBase._reportMissingRootWS (ParserMinimalBase.java:463)
com.fasterxml.jackson.core.json.ReaderBasedJsonParser._verifyRootSpace (ReaderBasedJsonParser.java:1236)
com.fasterxml.jackson.core.json.ReaderBasedJsonParser._parsePosNumber (ReaderBasedJsonParser.java:886)
com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken (ReaderBasedJsonParser.java:680)
cheshire.parse$parse.invokeStatic (parse.clj:87)
cheshire.parse$parse.invoke (parse.clj:85)
cheshire.core$parse_string.invokeStatic (core.clj:153)
cheshire.core$parse_string.invoke (core.clj:142)
cheshire.core$parse_string.invokeStatic (core.clj:149)
cheshire.core$parse_string.invoke (core.clj:142)
leiningen.cljs_lambda.aws$get_function_configuration_BANG_.invokeStatic (aws.clj:150)
leiningen.cljs_lambda.aws$get_function_configuration_BANG_.invoke (aws.clj:143)
leiningen.cljs_lambda.aws$deploy_function_BANG_.invokeStatic (aws.clj:187)
leiningen.cljs_lambda.aws$deploy_function_BANG_.invoke (aws.clj:185)
leiningen.cljs_lambda.aws$deploy_BANG_$fn__1213.invoke (aws.clj:214)
clojure.lang.AFn.applyToHelper (AFn.java:154)
clojure.lang.AFn.applyTo (AFn.java:144)
clojure.core$apply.invokeStatic (core.clj:646)
clojure.core$with_bindings_STAR_.invokeStatic (core.clj:1881)
clojure.core$with_bindings_STAR_.doInvoke (core.clj:1881)
clojure.lang.RestFn.invoke (RestFn.java:442)
leiningen.cljs_lambda.aws$do_functions_BANG_$iter__1187__1191$fn__1192$fn__1193$fn__1194.invoke (aws.clj:205)
clojure.lang.AFn.call (AFn.java:18)
java.util.concurrent.FutureTask.run (FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:617)
java.lang.Thread.run (Thread.java:745)
Output of lein cljs-lambda invoke
isn't machine-readable due to the commands being echoed, etc. - we should probably print that stuff to stderr and/or add a :quiet option
There's new switch in the awscli for update-function-configuration:
--tracing-config (structure)
The parent object that contains your function's tracing settings.
Shorthand Syntax:
Mode=string
JSON Syntax:
{
"Mode": "Active"|"PassThrough"
}
It's AWS X-Ray related and I would like to add support for it. Proposal is:
:defaults {:tracing :active}
:tracing
can be used in :defaults
and per lambda function:tracing
values can be :active
or :passthrough
:tracing
is not provided, it defaults to :passthrough
It defaults to :passthrough
, because it's a default value for all AWS Lambda functions (checked via awscli).
Okay?
Would you be open to including boot support? I am happy to submit a PR for this feature.
Hi again!
This is a small improvement and feature request I noticed would be awesome.
The docstring can be used for the AWS Lambda description.
At the moment they are empty (I am using serverless-cljs-plugin
).
Thanks as usual for your work and this plugin ;)
It would be enlightening to see how to idiomatically use async-lambda-fn
together with external calls, for example to dynamodb. The callbacks there return either an Error or the result. I'm sure channels can be used to an advantage here, but I'll need an example to really grasp it.
Hi! What's the strategy for keywordizing keys and values?
If I invoke with eg
lein cljs-lambda invoke myFn '{"foo":"bar"}',
,
it arrives in my deflambda
as {:foo :bar}
.
This seems a bit too magical to me, as I might want {"foo" "bar"}
, {:foo "bar"}
or maybe even {"foo" :bar}
. It probably should be up to the implementer.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.