1

我正在使用 Rhino 通过 Java 解释 javascripts。我的用例需要这些 javascript 进行(多个)服务调用(RESTful/Webservices/HTTP GET/POST)。其中一些服务调用本质上是异步的(具有 24 小时 SLA)。

我希望能够在这种情况下暂停我的脚本的执行,序列化状态(将其保存在 S3 上,并将密钥传递给异步服务的有效负载,服务在回调时返回)并在我得到时恢复执行结果从服务中返回。

我面临的挑战是 ContinuationPending(扩展 RuntimeException)不可序列化(因为 Context 不可序列化)。

问题:有没有其他方法可以存储脚本的状态并从其序列化形式中取回?

Javascript:

function invokeFooService(arg) {
    return foo.bar.Helper.invokeFooServiceAsync(arg);
}

function main() {
    // Main JS function
    ..
    var response = invokeFooService(arg);
    if (..) {
        ..
    }
}

爪哇:

package foo.bar;

public class Helper {

    public static final void invokeFooServiceAsync(String arg) {
        Context cx = getContext();
        ContinuationPending pending = cx.captureContinuation();
        // At this point the script is paused
        // Serialize the state of script
        invokeFooService(arg, key);
    }

    public static final void returnResponse(FooResponse response, String key) {
        // De serialize the state of script
        ContinuationPending pending = ..
        Context cx = getContext();
        cx.resumeContinuation(pending.getContinuation(), getScope(), response);
        // Script is resumed
    }
}
4

1 回答 1

4

我终于找到了解决方案。关键是使用 ScriptableOutputStream(进行序列化)和 ScriptableInputStream(进行反序列化)Continuation 和 Scope。

下面是工作代码。

Javascript:

function invokeFooService(arg) {
    return foo.bar.Helper.invokeFooServiceAsync(arg);
}

function main() {
    // Main JS function
    ..
    var response = invokeFooService(arg);
    if (..) {
        ..
    }
}

爪哇:

package foo.bar;

public class Helper {

    public static final void invokeFooServiceAsync(String arg) {
        Context cx = getContext();
        ContinuationPending pending = cx.captureContinuation();
        // Script is paused here
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ScriptableOutputStream sos = new ScriptableOutputStream(baos, getScope());
        sos.writeObject(pending.getContinuation());
        sos.writeObject(getScope());
        String servicePayload = Base64.encodeBase64String(baos.toByteArray());
        invokeFooServiceForReal(arg, servicePayload); // This method invokes the async service
    }

    public static final void returnFooServiceResponse(FooResponse response, String servicePayload) {
        // De serialize the state of script
        byte[] continuationAndScope = Base64.decodeBase64(servicePayload);
        ScriptableInputStream sis = new ScriptableInputStream(new ByteArrayInputStream(continuationAndScope), getScope());
        Scriptable continuation = (Scriptable) sis.readObject();
        Scriptable scope = (Scriptable) sis.readObject();
        getContext().resumeContinuation(continuation, scope, response);
        // Script resumed
    }
}
于 2014-09-15T09:18:05.240 回答