Skip to content

Commit 3cd96de

Browse files
committed
fix: refactor engine creation in JSPlugin and JSInterceptorFactory to use PolyglotThreadUtils for platform thread compatibility and add test for virtual thread offloading
#663
1 parent c367940 commit 3cd96de

3 files changed

Lines changed: 31 additions & 11 deletions

File tree

polyglot/src/main/java/org/restheart/polyglot/JSPlugin.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
*/
2121
package org.restheart.polyglot;
2222

23-
import java.io.IOException;
2423
import java.util.Map;
2524
import java.util.Optional;
2625

@@ -40,11 +39,11 @@ public abstract class JSPlugin {
4039

4140
static {
4241
try {
43-
// use PluginsClassloader so ServiceLoader can find js-language's TruffleLanguageProvider
44-
engine = PolyglotClassloaderHelper.withPluginsClassloaderResult(Engine::create);
45-
} catch (IOException e) {
46-
// Engine.create() does not throw a checked exception; this cannot happen
47-
throw new IllegalStateException(e);
42+
// Engine.create() touches Truffle thread locals, must run on a platform thread (see PolyglotThreadUtils)
43+
// and needs PluginsClassloader so ServiceLoader can find js-language's TruffleLanguageProvider
44+
engine = PolyglotThreadUtils.onPlatformThread(() -> PolyglotClassloaderHelper.withPluginsClassloaderResult(Engine::create));
45+
} catch (Exception e) {
46+
throw new IllegalStateException("Error creating polyglot Engine", e);
4847
}
4948
}
5049

polyglot/src/main/java/org/restheart/polyglot/interceptors/JSInterceptorFactory.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ public JSInterceptorFactory(Optional<MongoClient> mclient, Configuration config)
6666
this.mclient = mclient;
6767
this.config = config;
6868
try {
69-
// use PluginsClassloader so ServiceLoader can find js-language's TruffleLanguageProvider
70-
this.engine = PolyglotClassloaderHelper.withPluginsClassloaderResult(Engine::create);
71-
} catch (IOException e) {
72-
// Engine.create() does not throw a checked exception; this cannot happen
73-
throw new IllegalStateException(e);
69+
// Engine.create() touches Truffle thread locals, must run on a platform thread (see PolyglotThreadUtils)
70+
// and needs PluginsClassloader so ServiceLoader can find js-language's TruffleLanguageProvider
71+
this.engine = PolyglotThreadUtils.onPlatformThread(() -> PolyglotClassloaderHelper.withPluginsClassloaderResult(Engine::create));
72+
} catch (Exception e) {
73+
throw new IllegalStateException("Error creating polyglot Engine", e);
7474
}
7575
}
7676

polyglot/src/test/java/org/restheart/polyglot/ContextQueueVirtualThreadTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,25 @@ void executeWithContextSucceedsWhenCalledFromVirtualThread() throws Exception {
112112
assertNull(failure.get(), () -> String.valueOf(failure.get()));
113113
assertEquals(42, result.get());
114114
}
115+
116+
@Test
117+
void engineCreateSucceedsWhenOffloadedFromVirtualThread() throws Exception {
118+
// mirrors how JSPlugin/JSInterceptorFactory build their static Engine field
119+
var result = new AtomicReference<Engine>();
120+
var failure = new AtomicReference<Throwable>();
121+
122+
var vt = Thread.ofVirtual().unstarted(() -> {
123+
try {
124+
result.set(PolyglotThreadUtils.onPlatformThread(Engine::create));
125+
} catch (Throwable t) {
126+
failure.set(t);
127+
}
128+
});
129+
130+
vt.start();
131+
vt.join();
132+
133+
assertNull(failure.get(), () -> String.valueOf(failure.get()));
134+
result.get().close();
135+
}
115136
}

0 commit comments

Comments
 (0)