requestTimeout: I think this should default to 900 so it is never shorter than the Lambda timeout and have a note that explains that the runtime is actually configured by the Lambda configuration
sessionTimeout: shouldn’t this default to 0?
logging: I think the default configuration should append to the console.
executors: does this even make sense for a Lambda? If it does, surely only for virtual threads or a ForkJoinPool that is disabled by default I think.
caches: how needed is this?
Other random stuff:
I could not get any code to run during the static initialization. I don’t suppose there is any trick to have a static onApplicationStart() is there?
Cold start time went down to 1200 ms init and 800 ms first run (with 8 GB on ARM), then 8 ms on next requests. Do you see that improving significantly in the future, for instance with GraalVM or when the .bx files are precompiled?
I have done all the updates, I am marking them below.
1. timezone: this should probably refer to the TZ environment variable in a comment 2. requestTimeout: I think this should default to 900 so it is never shorter than the Lambda timeout and have a note that explains that the runtime is actually configured by the Lambda configuration 3. sessionTimeout: shouldn’t this default to 0? 4. logging: I think the default configuration should append to the console.
Thanks for this one as this was not an option in BoxLang. I added this in the upcoming 1.2, as a way for you to chose your appender: console or file. You can also chose your encoder now for each to text or json.
executors: does this even make sense for a Lambda? If it does, surely only for virtual threads or
a ForkJoinPool that is disabled by default I think.
The 3 executors must remain in order for internal operations to work, and also if the user does something with parallel executions, which might be the case. Granted, they could do I/O bound processes or CPU bound, I don’t know that, so that will have to remain a case for the user.
caches: how needed is this?
This can be needed, if you connect the caches to a file store or a jdbc store or redis, etc. So in reality, the caches, is totally up to the user. Having the basic caching is enough for in-memory transactioning that can happen. However, this is totally customizable. You could do a s3 mount, or ElastiCache, etc.
Thanks so much for the updates. You can find them in the template now.
And in the buildLambdaZip I changed the path of the file to include and added a dependsOn:
/**
* Build the Lambda zip file for deployment on AWS
*/
task buildLambdaZip( type: Zip ) {
dependsOn( 'compileBoxlang' )
archiveFileName = "${project.name}-${version}.zip"
// Add Lambda.bx to the root of the ZIP
from './build/compiled/main/bx/Lambda.bx'
...
That was building fine, but when I tested after deployment I got:
The source file /var/task/Lambda.bx is pre-compiled bytecode, but its original class name [boxgenerated.boxclass.Lambda$bx] does not match what we expected [boxgenerated.boxclass.var.task.Lambda$bx]. Pre-compiled source code must have the same path and name as the original file.
Moving the file from src/main/bx/Lambda.bx to src/main/bx/var/task/Lambda.bx made that work. But that is obviously not nice. Changing the basePath to /var/task is not working either, because the source must be a subdirectoy of the basePath.
Some workaround would be really nice because it looks like the first request is about 400 ms faster with precompiled code
More observations:
I noticed that a fileRead( expandPath( "./boxlang.json" ) expanded to a path on my workstation. Is expandPath resolved at compile time instead of runtime?
would it hypothetically be possible to reduce the size of the runtime further if you are only deploying precompiled code? For instance, strip out ortus.boxlang.compiler and ortus.boxlang.parser?
the build.gradle includes 'src/test/resources/libs' in the zip. I presume that addition of test libs is a mistake
The file [/home/jochem/boxlang/bx-aws-lambda-template/src/main/bx/var/task/boxlang.json] could not be found or does not exist.
I can already confirm that removing the parser and the javacompiler is possible (unzip, delete, zip) for the Lambda above. It reduced the Lambda size by about 1.3 MB. Cold start time might be about 60 ms lower.
expandPath() is defo evaluated at runtime based on the current mappings. I wouldn’t recommend using a . in paths as that’s not really a documented behavior in CF/BL. It often times works because the underlying Java file system will use it to reference the working directory of the java process, but that is not a very portable concept in most use cases. It’s more idiomatic to resolve relative to the existing template (no leading slash, and no dot) or relative to a known mapping.
Am I understanding you to say that the code
expandPath( "./boxlang.json" )
is running inside a Lambda on AWS, but expanding to a path on your local PC? That makes no sense to me at all and I can’t imagine how what would ever happen unless you somehow shipping some mappings set up in the application.bx or in the boxlang.json which were hard-coded to this path.
Precompilation of source files is an experimental feature and the checks to ensure the class name haven’t changed are a bit of a pain right now. That is enforced by Java’s classloader as it will refuse the load the class if the bytecode doesn’t match the class name that it was expecting. I have some ideas to try and modify the bytecode on the fly to match whatever name we expected, but haven’t had a chance to try them. So right now, I just catch those scenarios and throw the error you see. What that means is that the class must be in the same folder structure and accessed in the same manner at compile time as it will be accessed at runtime. But even this isn’t a perfect fix as more than one relative mapping can provide more than one valid path to a class which only exists once on disk physically, making it impossible to create it via more than one path. This is why I need to figure out how to rewrite the bytecode on the fly, if possible.
Our lambda runner could prolly make this easier if it were to create the class via a mapping instead of using what I assume is the full path from the root of the file system var.task.Lambda. I’m unclear about how Lambda work however to know where the “working directory” of the JVM process points to. This is also the default location of the / mapping (or web root as we would call it in a web server context) unless Luis has done something to change that default in our Lambda templates.
Yes. I showed in the code I used to compile and the full body of Lambda.bx. There is no Application.bx or any other change to the boxlang.json, just compiled before packaging and deployment to AWS Lambda.
Oh, if the path is being expanded relative to the currently executing template, then it may be getting the path from the byte code if the template, which was generated on your PC. Any idea how CF handles this?
No, I’m asking how CF resolves paths relative to a template when the template is precompiled. We hard code the file path into the bytecode at compile time. At runtime, the bytecode is simply loaded with no regard to where it may live now.
Don’t know how, it just worked. But I think I have settled on mounting the code into a Docker container at the /var/task path and compiling there so it will have the same path during compilation as I will have at runtime.
The ${env:TZ:UTC} in the boxlang.json doesn’t work right. At startup it complains that TZ:UTC is not a valid timezone.