Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fails to load when used in AWS Lambda function #175

Closed
chris opened this issue Mar 22, 2018 · 16 comments
Closed

Fails to load when used in AWS Lambda function #175

chris opened this issue Mar 22, 2018 · 16 comments
Assignees
Labels
Milestone

Comments

@chris
Copy link

chris commented Mar 22, 2018

First, caveat I'm pretty new to Clojure. I have a small AWS Lambda function that will be a GraphQL endpoint. GraphQL code is working fine in tests and the REPL. However, as soon as I require com.walmartlabs.lacinia in any code, the Lambda fails to load, ultimately resulting in an "ANTLR ErrorManager panic" error. I get different stack traces depending on where it's required. Note, requiring the other parts of Lacinia (schema, util, resolve, etc.) all seem fine. Seems to have something to do with initial loading of ANTLR, although I'm able to load and parse my GraphQL schema with ...lacinia.schema/compile without problems. I'm using Lacinia 0.25.0, Clojure 1.9, Java 8.

If I have (:require [com.walmartlabs.lacinia :refer [execute]]) then I see:

ojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:551)
	at com.walmartlabs.lacinia$loading__6434__auto____1137.invoke(lacinia.clj:1)
	at com.walmartlabs.lacinia__init.load(Unknown Source)
	at com.walmartlabs.lacinia__init.<clinit>(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at clojure.lang.RT.classForName(RT.java:2204)
...

If I move that require to a different file, then I see:

ke(interpreted.clj:124)
	at clj_antlr.core$parser.invokeStatic(core.clj:67)
	at clj_antlr.core$parser.invoke(core.clj:47)
	at clj_antlr.core$parser.invokeStatic(core.clj:65)
	at clj_antlr.core$parser.invoke(core.clj:47)
	at com.walmartlabs.lacinia.parser__init.load(Unknown Source)
	at com.walmartlabs.lacinia.parser__init.<clinit>(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at clojure.lang.RT.classForName(RT.java:2204)
...

I'm hoping maybe I am missing something with my configuration or how I need to create my Uberjar or something? I am using :aot :all for the Uberjar. Maybe someone can give me some ideas on where to start investigating further?

@kgann
Copy link

kgann commented Mar 23, 2018

Can you provide the full stack traces? There should be a Caused by: ... clause followed by some useful details.

🏩

@chris
Copy link
Author

chris commented Mar 23, 2018

Hey Kyle ;-) The trace seems maybe different/truncated due to being in Lambda env - there's no "Caused by:", but here's what I get as log output (sadly, the System.out.println's Antlr is doing don't seem to show up either, also that apparently cut beginning of "ke" is exactly the beginning I get, so something is cut off):

ke(interpreted.clj:124)
	at clj_antlr.core$parser.invokeStatic(core.clj:67)
	at clj_antlr.core$parser.invoke(core.clj:47)
	at clj_antlr.core$parser.invokeStatic(core.clj:65)
	at clj_antlr.core$parser.invoke(core.clj:47)
	at com.walmartlabs.lacinia.parser__init.load(Unknown Source)
	at com.walmartlabs.lacinia.parser__init.<clinit>(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at clojure.lang.RT.classForName(RT.java:2204)
	at clojure.lang.RT.classForName(RT.java:2213)
	at clojure.lang.RT.loadClassForName(RT.java:2232)
	at clojure.lang.RT.load(RT.java:450)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:551)
	at com.walmartlabs.lacinia$loading__6434__auto____5243.invoke(lacinia.clj:1)
	at com.walmartlabs.lacinia__init.load(Unknown Source)
	at com.walmartlabs.lacinia__init.<clinit>(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at clojure.lang.RT.classForName(RT.java:2204)
	at clojure.lang.RT.classForName(RT.java:2213)
	at clojure.lang.RT.loadClassForName(RT.java:2232)
	at clojure.lang.RT.load(RT.java:450)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:512)
	at good_shows.core$loading__6434__auto____5102.invoke(core.clj:1)
	at good_shows.core__init.load(Unknown Source)
	at good_shows.core__init.<clinit>(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at clojure.lang.RT.classForName(RT.java:2204)
	at clojure.lang.RT.classForName(RT.java:2213)
	at clojure.lang.RT.loadClassForName(RT.java:2232)
	at clojure.lang.RT.load(RT.java:450)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.lang.Var.invoke(Var.java:381)
	at clojure.lang.Util.loadWithClass(Util.java:250)
	at goodshows.lambda.GraphQLHandler.<clinit>(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)

END RequestId: 1d3fd043-2e51-11e8-b9fb-8fae04cb6b0c
REPORT RequestId: 1d3fd043-2e51-11e8-b9fb-8fae04cb6b0c	Duration: 2.82 ms	Billed Duration: 100 ms 	Memory Size: 1024 MB	Max Memory Used: 108 MB	

Also, it seems to me that it has something to do with initialization of Antlr. I pulled out the grammer initialization line out of Lacinia's parser, and removed my require, and just directly required Antlr, and put that grammer line in my code (to test this):

(def ^:private lacinia-grammar
  (antlr.core/parser (slurp (io/resource "com/walmartlabs/lacinia/Graphql.g4"))))

I then ran the Lambda, and got an error in Antlr's setFormat - here: https://github.com/antlr/antlr4/blob/4.5.3/tool/src/org/antlr/v4/tool/ErrorManager.java#L265 (4.5.3 is the Antlr version I found in the Lacinia deps), so it seems like it's not being able to find it's needed foramt file. But, this seems like it is missing the antlr.stg file, yet I look in my jar and I see it there, as org/antlr/v4/tool/templates/messages/formats/antlr.stg which matches what it seems the code is looking for. Tracing that, the location, message, and report items are in that file (which is what the verifyFormat bit checks for). So, I dunno if there's some kind of encoding thing, or something Lambda is doing weird with the Jar or what. I'll be trying to dig into this further, and/or see if there may be some oddity of the Lambda JVM environment.

@chris
Copy link
Author

chris commented Mar 23, 2018

@kgann doh, my bad - the logs from the test run are truncated. I got the full log, and voila, there's a Caused by, and that shows the reason!

Caused by: java.io.FileNotFoundException: /org/antlr/v4/tool/templates/messages/formats/antlr.stg (No such file or directory)

My guess is that the root-level path is causing problems. Also, even more odd, the code shows that it doesn't have that root path separator on the front when it constructs it, so maybe that's added somehow in the loading code. I will dig through and investigate more, but if this sheds any light, let me know.

Oh, and here's the full trace:

2018-03-23 04:17:40
can't load group file file:/org/antlr/v4/tool/templates/messages/formats/antlr.stg
Caused by: java.io.FileNotFoundException: /org/antlr/v4/tool/templates/messages/formats/antlr.stg (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90)
at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188)
at java.net.URL.openStream(URL.java:1045)
at org.stringtemplate.v4.STGroup.loadGroupFile(STGroup.java:607)
at org.stringtemplate.v4.STGroupFile.load(STGroupFile.java:139)
at org.antlr.v4.tool.ErrorManager.setFormat(ErrorManager.java:254)
at org.antlr.v4.Tool.<init>(Tool.java:218)
at org.antlr.v4.Tool.<init>(Tool.java:213)
at clj_antlr.interpreted$tool.invokeStatic(interpreted.clj:18)
at clj_antlr.interpreted$tool.invoke(interpreted.clj:18)
at clj_antlr.interpreted$load_string_grammar.invokeStatic(interpreted.clj:26)
at clj_antlr.interpreted$load_string_grammar.invoke(interpreted.clj:23)
at clj_antlr.interpreted$grammar.invokeStatic(interpreted.clj:38)
at clj_antlr.interpreted$grammar.invoke(interpreted.clj:32)
at clj_antlr.interpreted$parser.invokeStatic(interpreted.clj:127)
at clj_antlr.interpreted$parser.invoke(interpreted.clj:124)
at clj_antlr.core$parser.invokeStatic(core.clj:67)
at clj_antlr.core$parser.invoke(core.clj:47)
at clj_antlr.core$parser.invokeStatic(core.clj:65)
at clj_antlr.core$parser.invoke(core.clj:47)
at com.walmartlabs.lacinia.parser__init.load(Unknown Source)
at com.walmartlabs.lacinia.parser__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2204)
at clojure.lang.RT.classForName(RT.java:2213)
at clojure.lang.RT.loadClassForName(RT.java:2232)
at clojure.lang.RT.load(RT.java:450)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:551)
at com.walmartlabs.lacinia$loading__6434__auto____5243.invoke(lacinia.clj:1)
at com.walmartlabs.lacinia__init.load(Unknown Source)
at com.walmartlabs.lacinia__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2204)
at clojure.lang.RT.classForName(RT.java:2213)
at clojure.lang.RT.loadClassForName(RT.java:2232)
at clojure.lang.RT.load(RT.java:450)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:512)
at good_shows.core$loading__6434__auto____5102.invoke(core.clj:1)
at good_shows.core__init.load(Unknown Source)
at good_shows.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2204)
at clojure.lang.RT.classForName(RT.java:2213)
at clojure.lang.RT.loadClassForName(RT.java:2232)
at clojure.lang.RT.load(RT.java:450)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:381)
at clojure.lang.Util.loadWithClass(Util.java:250)
at goodshows.lambda.GraphQLHandler.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.HandlerInfo.fromString(HandlerInfo.java:31)
at lambdainternal.AWSLambda.findUserMethods(AWSLambda.java:93)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:254)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94)

Format template 'location' not found in antlr
Format template 'message' not found in antlr
Format template 'report' not found in antlr
ANTLR installation corrupted; ANTLR messages format file antlr.stg incomplete
START RequestId: 1d3fd043-2e51-11e8-b9fb-8fae04cb6b0c Version: $LATEST
ANTLR ErrorManager panic: java.lang.Error
java.lang.Error: ANTLR ErrorManager panic
at org.antlr.v4.tool.ErrorManager.panic(ErrorManager.java:320)
at org.antlr.v4.tool.ErrorManager.setFormat(ErrorManager.java:265)
at org.antlr.v4.Tool.<init>(Tool.java:218)
at org.antlr.v4.Tool.<init>(Tool.java:213)
at clj_antlr.interpreted$tool.invokeStatic(interpreted.clj:18)
at clj_antlr.interpreted$tool.invoke(interpreted.clj:18)
at clj_antlr.interpreted$load_string_grammar.invokeStatic(interpreted.clj:26)
at clj_antlr.interpreted$load_string_grammar.invoke(interpreted.clj:23)
at clj_antlr.interpreted$grammar.invokeStatic(interpreted.clj:38)
at clj_antlr.interpreted$grammar.invoke(interpreted.clj:32)
at clj_antlr.interpreted$parser.invokeStatic(interpreted.clj:127)
at clj_antlr.interpreted$parser.invoke(interpreted.clj:124)
at clj_antlr.core$parser.invokeStatic(core.clj:67)
at clj_antlr.core$parser.invoke(core.clj:47)
at clj_antlr.core$parser.invokeStatic(core.clj:65)
at clj_antlr.core$parser.invoke(core.clj:47)
at com.walmartlabs.lacinia.parser__init.load(Unknown Source)
at com.walmartlabs.lacinia.parser__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2204)
at clojure.lang.RT.classForName(RT.java:2213)
at clojure.lang.RT.loadClassForName(RT.java:2232)
at clojure.lang.RT.load(RT.java:450)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:551)
at com.walmartlabs.lacinia$loading__6434__auto____5243.invoke(lacinia.clj:1)
at com.walmartlabs.lacinia__init.load(Unknown Source)
at com.walmartlabs.lacinia__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2204)
at clojure.lang.RT.classForName(RT.java:2213)
at clojure.lang.RT.loadClassForName(RT.java:2232)
at clojure.lang.RT.load(RT.java:450)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:512)
at good_shows.core$loading__6434__auto____5102.invoke(core.clj:1)
at good_shows.core__init.load(Unknown Source)
at good_shows.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2204)
at clojure.lang.RT.classForName(RT.java:2213)
at clojure.lang.RT.loadClassForName(RT.java:2232)
at clojure.lang.RT.load(RT.java:450)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:381)
at clojure.lang.Util.loadWithClass(Util.java:250)
at goodshows.lambda.GraphQLHandler.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)

@kgann
Copy link

kgann commented Mar 23, 2018

I just created a "hello world" project and ran it on AWS Lambda. Unfortunately I encountered the same issue.

ANTLR ErrorManager panic
Caused by: java.io.FileNotFoundException: /org/antlr/v4/tool/templates/messages/formats/antlr.stg (No such file or directory)

I'll keep exploring this issue and have my team of 🅰️+ engineers get to work on it.

@chris
Copy link
Author

chris commented Mar 23, 2018

As a note, I know there are newer versions of Antlr. I did a quick try of pulling down clj-antlr, and updating it's Antlr dependency to 4.7.1 (which I believe is the latest). Unfortunately the tests failed.

@solussd
Copy link

solussd commented Apr 1, 2018

I am also experiencing this issue when deployed to AWS as a lambda. Here's another datapoint: It does not manifest itself when pointing to an unzipped .jar directory using sam-local.

@solussd
Copy link

solussd commented Apr 10, 2018

Has anyone found a workaround for this?

@kgann
Copy link

kgann commented Apr 13, 2018

I'm still banging my head on this one. The ANTLR resource is available on the classpath so that is a bit of a red herring.

@solussd
Copy link

solussd commented Apr 13, 2018

The fact that it works locally using SAM Local might mean that the classpath is being constructed differently on AWS.

@solussd
Copy link

solussd commented Apr 19, 2018

I've figured this one out, though I'm still working through how to fix/workaround it.

The tl;dr is: AWS Lambda unpacks your jar into a directory off root defined by the env var "LAMBDA_TASK_ROOT", but ANTLR, by way of the StringTemplate4 library and several coercions to/from string, url, uri types, ends up constructing a resource path rooted at /. To make matters worse, ANTLR and StringTemplate4 look for the format filename differently (so you could construct a valid absolute path in antlr to pass to stringtemplate and have it fail the checks in antlr, which correctly use a call to classLoader getResource.

Here is a hacky workaround for the Antlr's ErrorManager class's setFormat method (v0.5.4-SNAPSHOT, check out tag 4.5.3). Rebuilding with this "fixes" it. Also, add SkipTests when doing a Maven install. Tests are broken. Note that I construct a file path with the value of LAMBDA_TASK_ROOT to pass to StringTemplate's STGroupFile constructor. Antlr handles the relative path just fine.

    public void setFormat(String formatName) {
        this.formatName = formatName;
        String lambdaTaskRoot = System.getenv("LAMBDA_TASK_ROOT");
        String fileName = FORMATS_DIR +formatName+STGroup.GROUP_FILE_EXTENSION;
        String fileNameForStringTemplateLib =  (lambdaTaskRoot != null ? lambdaTaskRoot + "/" : "") + fileName;
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        URL url = cl.getResource(fileName);
        if ( url==null ) {
            cl = ErrorManager.class.getClassLoader();
            url = cl.getResource(fileName);
        }
        if ( url==null && formatName.equals("antlr") ) {
            rawError("ANTLR installation corrupted; cannot find ANTLR messages format file "+fileName);
            panic();
        }
        else if ( url==null ) {
            rawError("no such message format file "+fileName+" retrying with default ANTLR format");
            setFormat("antlr"); // recurse on this rule, trying the default message format
            return;
        }
        STGroupFile.verbose = true;
        format = new STGroupFile(fileNameForStringTemplateLib, "UTF-8");
        format.load();

        if ( !initSTListener.errors.isEmpty() ) {
            rawError("ANTLR installation corrupted; can't load messages format file:\n"+
                     initSTListener.toString());
            panic();
        }

        boolean formatOK = verifyFormat();
        if ( !formatOK && formatName.equals("antlr") ) {
            rawError("ANTLR installation corrupted; ANTLR messages format file "+formatName+".stg incomplete");
            panic();
        }
        else if ( !formatOK ) {
            setFormat("antlr"); // recurse on this rule, trying the default message format
        }
    }

@solussd
Copy link

solussd commented Apr 23, 2018

In the version of Antlr used by this library's clj-antlr dependency it is enough to replace format = new STGroupFile(fileName, "UTF-8"); with format = new STGroupFile(url.getPath(), "UTF-8");. I set about testing w/ Antlr4 master and making the necessary changes, but the changes are no longer so straightforward. There are more places that filepaths are mishandled by StringTemplate4.

@solussd
Copy link

solussd commented Apr 24, 2018

I modified ANTLR and Stringtemplate4 to get this working in all deployment scenarios (AOT'd packed jar, AOT'd unpacked jar, repl).

PRs here:
antlr/antlr4#2280
antlr/stringtemplate4#199

and I have forks of both libs with the changes:
https://github.com/solussd/antlr4
https://github.com/solussd/stringtemplate4

Simply exclude the org.antlr/antlr4 and org.antlr/antlr4-runtime transitive deps to Lacinia and replace with their respective 4.7.2-SNAPSHOTs built/installed from above.

In the meantime ... what's the level of effort to use Instaparse instead? :)

@kgann
Copy link

kgann commented May 2, 2018

In the meantime ... what's the level of effort to use Instaparse instead? :)

We used Instaparse at first but noticed extremely high query parse times for large queries. We moved to Antlr to improve performance.

@solussd
Copy link

solussd commented May 2, 2018

I'm worried that Antlr4 and StringTemplate4 are abandoned. 48 open PRs and hundreds of issues against Antlr, likewise many open for ST4. I don't think my PRs will be merged anytime soon.

@chris
Copy link
Author

chris commented May 25, 2018

@solussd thank you! For any other folks who might come across this and not know the Leiningen and build mechanisms for what @solussd describes above, what I did (and please tell me if there's a better way!) was:

  • clone each of @solussd 's forks
  • In antlr4, ran export MAVEN_OPTS="-Xmx1G" && mvn install -DskipTests=true per the Antlr build page. Also, they were right that without that export/MAVEN_OPTS, it didn't successfully build.
  • In stringtemplate4 ran mvn install
  • In my project's project.clj, changed my Lacinia dependency to have the excludes, and then include the forks with:
                 [org.antlr/antlr4 "4.7.2-SNAPSHOT"]
                 [org.antlr/antlr4-runtime "4.7.2-SNAPSHOT"]
                 [com.walmartlabs/lacinia "0.26.0" :exclusions [org.antlr/antlr4 org.antlr/antlr4-runtime]

Rebuilt everything (and also had to make sure Cursive reparsed Maven as the REPL wasn't working properly until I did that, in case you use Cursive ;-).

@solussd
Copy link

solussd commented Nov 13, 2018

Update: this issue is fixed upstream now in ANTLR4 4.7.2-SNAPSHOT.

kahunamoore added a commit to kahunamoore/clj-antlr that referenced this issue Jan 23, 2019
Fixes file/path open problem on AWS lambda, see:

antlr/antlr4#2280
antlr/antlr4@11d6013

Needed by an open Lacinia issue:

walmartlabs/lacinia#175 (comment)
@hlship hlship added the bug label Sep 10, 2019
@hlship hlship added this to the 0.35.0 milestone Sep 10, 2019
@hlship hlship self-assigned this Sep 10, 2019
@hlship hlship closed this as completed in 8f51e21 Sep 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants