Amazon DynamoDB Local - 未知错误,异常或失败
Amazon DynamoDB Local - 未知错误,异常或失败
我需要测试一个严重依赖于亚马逊的DynamoDB的应用程序。我希望能够分别运行这些测试,这就是为什么我选择了DynamoDB Local .jar
。我知道最近的更新使我们能够在不调用外部bash命令的情况下运行它。然而,当我尝试运行这里指定的示例时,我得到以下堆栈跟踪:
Exception in thread "main" com.amazonaws.AmazonServiceException: 由于未知错误、异常或故障,请求处理失败。(服务:AmazonDynamoDBv2;状态码:500;错误代码:InternalFailure;请求ID:cab7a550-aaa6-4bfe-a591-0b255481cc14) at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1275) at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:873) at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:576) at com.amazonaws.http.AmazonHttpClient.doExecute(AmazonHttpClient.java:362) at com.amazonaws.http.AmazonHttpClient.executeWithTimer(AmazonHttpClient.java:328) at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:307) at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.invoke(AmazonDynamoDBClient.java:1805) at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.listTables(AmazonDynamoDBClient.java:1223) at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.listTables(AmazonDynamoDBClient.java:1235)
这是我尝试运行的代码:
public static void main( String[] args ) throws Exception { AmazonDynamoDB dynamodb = null; DynamoDBProxyServer server = null; final String[] localArgs = { "-inMemory", "-port", "13005" }; server = ServerRunner.createServerFromCommandLineArgs(localArgs); server.start(); BasicAWSCredentials auth = new BasicAWSCredentials("key", "secret"); dynamodb = new AmazonDynamoDBClient(auth); dynamodb.setEndpoint("http://127.0.0.1:13005"); // use the DynamoDB API over HTTP System.out.println(dynamodb.listTables()); // Stop the DynamoDB Local endpoint if(server != null) { server.stop(); } }
我观察到,如果我尝试完全从Java程序本身运行它,就会抛出异常,并且指定的端口不再可用(抛出错误,指出此端口被占用)。但是,如果我从命令提示符中启动DynamoDB Local,并将Java程序仅用作访问客户端,则一切都正常运行。
有什么建议吗?
2018年8月,亚马逊宣布推出了带有Amazon DynamoDB Local的新的Docker镜像。使用这个镜像不再需要下载和运行任何JAR文件,也不需要使用第三方特定操作系统的二进制文件(我指的是sqlite4java
)。
使用Docker容器非常简单,只需要在运行测试之前启动一个Docker容器即可:
docker run -p 8000:8000 amazon/dynamodb-local
你可以在本地开发时手动执行上述操作。IDE通常提供在执行任务之前运行任意命令的方法,所以你可以让IDE为你启动容器。
或者你可以在CI流水线中使用它。许多CI服务提供在流水线期间启动额外容器的能力,这些容器可以为你的测试提供依赖项。以下是Gitlab CI/CD的一个示例:
test:
stage: test
image: openjdk:8-alpine
services:
- name: amazon/dynamodb-local
alias: dynamodb-local
script:
- DYNAMODB_LOCAL_URL=http://dynamodb-local:8000 ./gradlew clean test
或者Bitbucket Pipelines的示例:
definitions:
services:
dynamodb-local:
image: amazon/dynamodb-local
…
step:
name: test
image:
name: openjdk:8-alpine
services:
- dynamodb-local
script:
- DYNAMODB_LOCAL_URL=http://localhost:8000 ./gradlew clean test
Amazon DynamoDB Local - 未知错误、异常或故障
在使用DynamoDBLocal时,至少存在两个问题。解决这两个问题,您将能够运行内嵌的DynamoDB。
首先,"-port"参数不起作用。因此,Jetty没有在您期望的端口上进行设置。而是将类似51205(或随机值?)设置为默认端口的Jetty监听器。
下面是我启动服务器的代码,避免使用内置的命令行解析,这种方式更好...以这种方式启动服务器后,"http://localhost:19444/shell"可以正常工作,所以Jetty没问题。但是,您可能会遇到另一个关于Sqlite4java的问题(请参见代码块后面的说明)。
注意:代码是Kotlin编写的,但Java的写法非常类似。此外,我已配置了SLF4j,并且不会让ServerRunner类破坏记录日志,所以这是启动服务器的更好方式,也是ServerRunner在内部执行的方式。
class TestAccountManager {
companion object {
private val localDbPort = 19444
private lateinit var localDb: DynamoDBProxyServer
private lateinit var dbClient: AmazonDynamoDBClient
fun setup() {
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.Slf4jLog")
localDb = DynamoDBProxyServer(localDbPort, LocalDynamoDBServerHandler(
LocalDynamoDBRequestHandler(0, true, null, true, true), null)
)
localDb.start()
val auth = BasicAWSCredentials("fakeKey", "fakeSecret")
dbClient = AmazonDynamoDBClient(auth)
dbClient.signerRegionOverride = "us-east-1"
dbClient.setEndpoint("http://localhost:$localDbPort")
}
fun teardown() {
localDb.stop()
}
}
fun testSomething() {
dbClient.listTables().tableNames.forEach {
println(it)
}
}
}
使用这段代码,您现在可以在预期的端口上运行了。
现在,您可能会遇到第二个错误,例如Sqlite4java无法找到适用于您平台的正确二进制文件。对于某些Mac OSX版本,它将生成一个实际上不存在的二进制文件名。而且DynamoDBLocal强制隐藏了所有Sqlite4java的日志记录(无法覆盖它),因此您无法看到它。
您可以通过下载一个分发版来测试sqlite库,然后解压并运行:
java -jar sqlite4java-1.0.392.jar -d
它将报告它尝试加载的内容以及加载是否失败。您只需要从Gradle、Maven或其他位置在系统中找到该JAR文件。我遇到的错误输出如下:
sqlite4java 392
160212:002049.833 FINE [sqlite] Internal: loading library
160212:002049.834 FINE [sqlite] Internal: java.library.path=/Users/jminard/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
160212:002049.834 FINE [sqlite] Internal: sqlite4java.library.path=null
160212:002049.834 FINE [sqlite] Internal: cwd=/Users/jminard/DEV/Collokia/repos/collokia-web-back/.
160212:002049.834 FINE [sqlite] Internal: default path=/Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d
160212:002049.834 FINE [sqlite] Internal: forced path=null
160212:002049.834 FINE [sqlite] Internal: os.name=mac os x; os=osx
160212:002049.835 FINE [sqlite] Internal: os.arch=x86_64
160212:002049.835 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-x86_64-1.0.392.dylib
160212:002049.835 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-amd64-1.0.392.dylib
160212:002049.835 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-1.0.392.dylib
160212:002049.835 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-1.0.392.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-x86_64-d-1.0.392.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-amd64-d-1.0.392.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-d-1.0.392.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-d-1.0.392.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-x86_64.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-amd64.dylib
160212:002049.836 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx.dylib
160212:002049.837 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java.dylib
160212:002049.837 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-x86_64-d.dylib
160212:002049.837 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-amd64-d.dylib
160212:002049.837 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-osx-d.dylib
160212:002049.837 FINE [sqlite] Internal: checking /Users/jminard/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/1.0.392/d6234e08ff4e1607ff5321da2579571f05ff778d/libsqlite4java-d.dylib
160212:002049.837 FINE [sqlite] Internal: trying to load sqlite4java-osx-x86_64-1.0.392
160212:002049.838 FINE [sqlite] Internal: cannot load sqlite4java-osx-x86_64-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-x86_64-1.0.392 in java.library.path
160212:002049.838 FINE [sqlite] Internal: trying to load sqlite4java-osx-amd64-1.0.392
160212:002049.839 FINE [sqlite] Internal: cannot load sqlite4java-osx-amd64-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-amd64-1.0.392 in java.library.path
160212:002049.839 FINE [sqlite] Internal: trying to load sqlite4java-osx-1.0.392
160212:002049.840 FINE [sqlite] Internal: cannot load sqlite4java-osx-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-1.0.392 in java.library.path
160212:002049.840 FINE [sqlite] Internal: trying to load sqlite4java-1.0.392
160212:002049.841 FINE [sqlite] Internal: cannot load sqlite4java-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-1.0.392 in java.library.path
160212:002049.841 FINE [sqlite] Internal: trying to load sqlite4java-osx-x86_64-d-1.0.392
160212:002049.842 FINE [sqlite] Internal: cannot load sqlite4java-osx-x86_64-d-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-x86_64-d-1.0.392 in java.library.path
160212:002049.842 FINE [sqlite] Internal: trying to load sqlite4java-osx-amd64-d-1.0.392
160212:002049.842 FINE [sqlite] Internal: cannot load sqlite4java-osx-amd64-d-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-amd64-d-1.0.392 in java.library.path
160212:002049.843 FINE [sqlite] Internal: trying to load sqlite4java-osx-d-1.0.392
160212:002049.843 FINE [sqlite] Internal: cannot load sqlite4java-osx-d-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-d-1.0.392 in java.library.path
160212:002049.843 FINE [sqlite] Internal: trying to load sqlite4java-d-1.0.392
160212:002049.844 FINE [sqlite] Internal: cannot load sqlite4java-d-1.0.392: java.lang.UnsatisfiedLinkError: no sqlite4java-d-1.0.392 in java.library.path
160212:002049.844 FINE [sqlite] Internal: trying to load sqlite4java-osx-x86_64
160212:002049.845 FINE [sqlite] Internal: cannot load sqlite4java-osx-x86_64: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-x86_64 in java.library.path
160212:002049.845 FINE [sqlite] Internal: trying to load sqlite4java-osx-amd64
160212:002049.845 FINE [sqlite] Internal: cannot load sqlite4java-osx-amd64: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-amd64 in java.library.path
160212:002049.845 FINE [sqlite] Internal: trying to load sqlite4java-osx
160212:002049.846 FINE [sqlite] Internal: cannot load sqlite4java-osx: java.lang.UnsatisfiedLinkError: no sqlite4java-osx in java.library.path
160212:002049.846 FINE [sqlite] Internal: trying to load sqlite4java
160212:002049.847 FINE [sqlite] Internal: cannot load sqlite4java: java.lang.UnsatisfiedLinkError: no sqlite4java in java.library.path
160212:002049.847 FINE [sqlite] Internal: trying to load sqlite4java-osx-x86_64-d
160212:002049.848 FINE [sqlite] Internal: cannot load sqlite4java-osx-x86_64-d: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-x86_64-d in java.library.path
160212:002049.848 FINE [sqlite] Internal: trying to load sqlite4java-osx-amd64-d
160212:002049.849 FINE [sqlite] Internal: cannot load sqlite4java-osx-amd64-d: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-amd64-d in java.library.path
160212:002049.849 FINE [sqlite] Internal: trying to load sqlite4java-osx-d
160212:002049.849 FINE [sqlite] Internal: cannot load sqlite4java-osx-d: java.lang.UnsatisfiedLinkError: no sqlite4java-osx-d in java.library.path
160212:002049.850 FINE [sqlite] Internal: trying to load sqlite4java-d
160212:002049.850 FINE [sqlite] Internal: cannot load sqlite4java-d: java.lang.UnsatisfiedLinkError: no sqlite4java-d in java.library.path
Error: cannot load SQLite
java.lang.UnsatisfiedLinkError: no sqlite4java-osx-x86_64-1.0.392 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1864)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at com.almworks.sqlite4java.Internal.tryLoadFromSystemPath(Internal.java:352)
at com.almworks.sqlite4java.Internal.loadLibraryX(Internal.java:124)
at com.almworks.sqlite4java.SQLite.main(SQLite.java:368)
如果您遇到关于动态库加载的错误,请阅读以下链接以解决问题:
- [UnsatisfiedLinkError with sqlite4java Jar on Mac OS X NetBeans](https://stackoverflow.com/questions/15559551)
- [UnsatisfiedLinkError with sqlite4java Jar on Mac OS X](https://stackoverflow.com/questions/14301562)
- 特别是与DynamoDBLocal相关的问题:[Run DynamoDB Local with the java command on Mac OS X](https://stackoverflow.com/questions/24894109)
- [https://groups.google.com/forum/#!topic/sqlite4java/9J1lmCuoKLA](https://groups.google.com/forum/#!topic/sqlite4java/9J1lmCuoKLA)
- [https://groups.google.com/forum/#!topic/sqlite4java/jhwt44nYGvw](https://groups.google.com/forum/#!topic/sqlite4java/jhwt44nYGvw)
似乎唯一可靠的解决方法是:
- 将从下载的[sqlite4java分发版](https://bitbucket.org/almworks/sqlite4java)中的库添加到已知位置,并设置系统属性`java.library.path`。
- 或者将从下载的[sqlite4java分发版](https://bitbucket.org/almworks/sqlite4java)中的库添加到`/Library/Java/Extensions`(仅适用于macOS)。
我通常采用第一种选项,将库添加到项目中,并确保构建时添加`-Djava.library.path=./lib/sqlite4java`,其中动态库被解压缩的位置。为了更可靠的测试,您可以在代码中以编程方式设置`java.library.path`,使用这个技巧(否则,在代码中设置时将被忽略):[http://blog.cedarsoft.com/2010/11/setting-java-library-path-programmatically/](http://blog.cedarsoft.com/2010/11/setting-java-library-path-programmatically/)
DynamoDBLocal隐藏了所有的Sqlite错误,因此您必须进行调试以找到静默失败。该库中充满了调整日志级别的内容,使得调试变得困难,因为它们破坏了您查看错误的能力。例如,每当打开SqlLite文件时(类`SQLiteDBAccess`):
LocalDBUtils.setLog4jToUtilsLogging("com.almworks.sqlite4java");
LocalDBUtils.setLog4jToUtilsLogging("com.almworks.sqlite4java.Internal");
java.util.logging.Logger.getLogger("com.almworks.sqlite4java").setLevel(Level.OFF);
java.util.logging.Logger.getLogger("com.almworks.sqlite4java.Internal").setLevel(Level.OFF);
尾注:我正在寻找替代方案,这不是地球上构建得最好的东西,查看DynamoDbLocal的代码和为其做出的决策对我来说没有给予太多信心。Alternator或Jcabi - Dynamo Mock是我接下来要尝试的。