Постановка проблемы
Один из лямбда-форматов, который принимает AWS, - это zip-файл со следующими
Все скомпилированные файлы классов и файлы ресурсов на уровне root .
Все необходимые файлы jar для запуска кода в каталоге / lib.
Какой самый простой способ упаковать проект java в этот формат с использованием sbt?
Рабочий пример в Gradle
AWS предоставляет пример в gradle который выполняет эту настройку.
Например, со следующим макетом проекта:
.
├── build.gradle
└── src
└── main
└── java
└── example
└── HelloWorldLambda.java
И HelloWorldLambda.java
:
package example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
public class HelloWorldLambda implements RequestHandler<SQSEvent, SomeResult> {
@Override
public SomeResult handleRequest(SQSEvent event, Context ctx) {
for (var record: event.getRecords()) {
System.out.println("Found message: " + record.getBody());
}
return new SomeResult("OK");
}
}
final class SomeResult {
private String result;
SomeResult(String result) {
this.result = result;
}
public String getResult() {
return this.result;
}
}
Тогда это build.gradle
со следующим приведет к правильному zip:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile (
'com.amazonaws:aws-lambda-java-core:1.2.0',
'com.amazonaws:aws-lambda-java-events:2.2.7'
)
}
task buildZip(type: Zip) {
from compileJava
from processResources
into('lib') {
from configurations.runtimeClasspath
}
}
build.dependsOn buildZip
Рабочий пример в SBT с использованием native-packager
Мне удалось получить следующую работу с использованием sbt и sbt-native-packager.
Макет проекта:
.
├── build.sbt
├── project
│ ├── build.properties
│ ├── plugins.sbt
│ └── project
└── src
└── main
└── java
└── example
└── HelloWorldLambda.java
build.properties:
sbt.version=1.3.8
plugins.sbt:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.6.1")
build.sbt:
import com.typesafe.sbt.SbtNativePackager.Universal
import com.typesafe.sbt.packager.MappingsHelper._
import sbt.File
val LambdaZip = config("lambdaZip")
lazy val root = project.in(file("."))
.enablePlugins(JavaAppPackaging)
.configs(LambdaZip)
.settings(Seq(
libraryDependencies ++= Seq(
"com.amazonaws" % "aws-lambda-java-core" % "1.2.0",
"com.amazonaws" % "aws-lambda-java-events" % "2.2.7",
),
topLevelDirectory := None,
maintainer := "maintainer@example.com"
) ++ inConfig(LambdaZip)(Seq(
(target in Universal) := {
target.value / "lambdaZip"
},
(mappings in Universal) := {
val deps = (mappings in Universal).value.flatMap {
case (file, name) if name != "lib/root.root-0.1.0-SNAPSHOT.jar" => Seq(file -> name)
case (jarToExtract, name) =>
val extractDir = (target in Universal).value / "extract"
val unzipped = IO.unzip(jarToExtract, extractDir).toSeq
relative(unzipped, Seq(extractDir))
}
deps
},
packageBin := {
val zip = (packageBin in Universal).value
zip
}
)))
Это работает, но я вижу следующие проблемы с ним:
- Требуется использование плагина
- Требуется вручную извлечь исходную флягу, разархивировать ее во временную папку каталог и создание сопоставления для них
- Требуется использование строкового фильтра для всех jar-файлов проекта, то есть g можно по ошибке распаковать архив с зависимостями, если фильтр недостаточно плотный.
Есть ли более чистый способ реализовать это?
Примечание: AWS Lambda также принимает толстые банки и есть плагины, такие как sbt-assembly, которые могут создавать такие толстые фляги. Я не спрашиваю, как построить толстую банку в sbt для использования с лямбдой.