I got a problem when building my quarkus application in native mode using the vertx-redis-client
I`m trying create a cache class with the methods to connect, set and add. When i use the set and the get method i trying to open a new redis connection.
Using ./mvnw compile quarkus:dev the application run ok. But, when i try to build a native image i receive the error:
Error: No instances of io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object io.netty.buffer.UnreleasableByteBuf
object io.vertx.core.buffer.impl.BufferImpl
object io.vertx.redis.client.impl.types.BulkType
method io.vertx.redis.client.impl.RESPParser.handle(Buffer)
Call path from entry point to io.vertx.redis.client.impl.RESPParser.handle(Buffer):
at io.vertx.redis.client.impl.RESPParser.handle(RESPParser.java:51)
at io.vertx.redis.client.impl.RESPParser.handle(RESPParser.java:25)
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:369)
at io.vertx.core.impl.WorkerContext.lambda$wrapTask$0(WorkerContext.java:35)
at io.vertx.core.impl.WorkerContext$$Lambda$547/789610232.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)
com.oracle.svm.core.util.UserError$UserException: No instances of io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object io.netty.buffer.UnreleasableByteBuf
object io.vertx.core.buffer.impl.BufferImpl
object io.vertx.redis.client.impl.types.BulkType
method io.vertx.redis.client.impl.RESPParser.handle(Buffer)
Call path from entry point to io.vertx.redis.client.impl.RESPParser.handle(Buffer):
at io.vertx.redis.client.impl.RESPParser.handle(RESPParser.java:51)
at io.vertx.redis.client.impl.RESPParser.handle(RESPParser.java:25)
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:369)
at io.vertx.core.impl.WorkerContext.lambda$wrapTask$0(WorkerContext.java:35)
at io.vertx.core.impl.WorkerContext$$Lambda$547/789610232.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)
at com.oracle.svm.core.util.UserError.abort(UserError.java:75)
at com.oracle.svm.hosted.FallbackFeature.reportAsFallback(FallbackFeature.java:223)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:737)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:526)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:444)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object io.netty.buffer.UnreleasableByteBuf
object io.vertx.core.buffer.impl.BufferImpl
object io.vertx.redis.client.impl.types.BulkType
method io.vertx.redis.client.impl.RESPParser.handle(Buffer)
Call path from entry point to io.vertx.redis.client.impl.RESPParser.handle(Buffer):
at io.vertx.redis.client.impl.RESPParser.handle(RESPParser.java:51)
at io.vertx.redis.client.impl.RESPParser.handle(RESPParser.java:25)
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:369)
at io.vertx.core.impl.WorkerContext.lambda$wrapTask$0(WorkerContext.java:35)
at io.vertx.core.impl.WorkerContext$$Lambda$547/789610232.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)
at com.oracle.graal.pointsto.constraints.UnsupportedFeatures.report(UnsupportedFeatures.java:130)
at com.oracle.graal.pointsto.BigBang.finish(BigBang.java:565)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:688)
... 7 more
My cache class:
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.vertx.core.Vertx;
import io.vertx.redis.client.Redis;
import io.vertx.redis.client.RedisAPI;
import io.vertx.redis.client.RedisOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.concurrent.CompletableFuture;
@ApplicationScoped
public class Cache {
Logger logger = LoggerFactory.getLogger(Cache.class);
RedisAPI redis;
@Inject
Vertx vertx;
private void verifyConnection() {
if(redis == null) {
CompletableFuture<RedisAPI> connectionResult = new CompletableFuture<RedisAPI>();
Redis.createClient(vertx, new RedisOptions())
.connect(onConnect -> {
if (onConnect.succeeded()) {
Redis client = onConnect.result();
connectionResult.complete(RedisAPI.api(client));
} else {
connectionResult.complete(null);
}
});
redis = connectionResult.join();
}
}
public String get (String key) {
verifyConnection();
CompletableFuture<String> lambdaResult = new CompletableFuture<>();
redis.get(key, res -> {
if (res.succeeded()) {
if (res.result() != null) {
lambdaResult.complete(res.result().toString());
} else {
lambdaResult.complete(null);
}
} else {
lambdaResult.complete(null);
}
});
return lambdaResult.join();
}
public void set(String key, String data) {
verifyConnection();
redis.append(key, data, res -> {
if (res.failed()) {
logger.error("Error to send data to Cache");
}
});
}
}
This is a sign that we will probably need an extension to make it work but you can try doing it in your application first by tweaking the GraalVM settings.
You can try making
io.vertx.redis.client.impl.RESPParser
initializable at runtime. You can check https://quarkus.io/guides/writing-native-applications-tips#delaying-class-initialization for more information about how to do that in your application.If you end up having it working, please report back on
quarkus-dev
as we have a Redis extension in the works and your feedback might be useful to the people that will work on it soon.