Skip to content

Commit 17cafa3

Browse files
authored
Merge pull request #2062 from cloudflare/kenton/rpc-output-gate
JSRPC: Honor output gates.
2 parents 4e282ed + 87cb256 commit 17cafa3

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

src/workerd/api/tests/js-rpc-test.js

+15-6
Original file line numberDiff line numberDiff line change
@@ -412,24 +412,33 @@ export let basicServiceBinding = {
412412
assert.strictEqual(await env.self.oneArg(3), 36);
413413
assert.strictEqual(await env.self.oneArgOmitCtx(3), 37);
414414
assert.strictEqual(await env.self.oneArgOmitEnvCtx(3), 6);
415-
assert.rejects(() => env.self.twoArgs(123, 2),
415+
await assert.rejects(() => env.self.twoArgs(123, 2), {
416+
name: "TypeError",
417+
message:
416418
"Cannot call handler function \"twoArgs\" over RPC because it has the wrong " +
417419
"number of arguments. A simple function handler can only be called over RPC if it has " +
418420
"exactly the arguments (arg, env, ctx), where only the first argument comes from the " +
419421
"client. To support multi-argument RPC functions, use class-based syntax (extending " +
420-
"WorkerEntrypoint) instead.");
421-
assert.rejects(() => env.self.noArgs(),
422+
"WorkerEntrypoint) instead."
423+
});
424+
await assert.rejects(() => env.self.noArgs(), {
425+
name: "TypeError",
426+
message:
422427
"Attempted to call RPC function \"noArgs\" with the wrong number of arguments. " +
423428
"When calling a top-level handler function that is not declared as part of a class, you " +
424429
"must always send exactly one argument. In order to support variable numbers of " +
425430
"arguments, the server must use class-based syntax (extending WorkerEntrypoint) " +
426-
"instead.");
427-
assert.rejects(() => env.self.oneArg(1, 2),
431+
"instead."
432+
});
433+
await assert.rejects(() => env.self.oneArg(1, 2), {
434+
name: "TypeError",
435+
message:
428436
"Attempted to call RPC function \"oneArg\" with the wrong number of arguments. " +
429437
"When calling a top-level handler function that is not declared as part of a class, you " +
430438
"must always send exactly one argument. In order to support variable numbers of " +
431439
"arguments, the server must use class-based syntax (extending WorkerEntrypoint) " +
432-
"instead.");
440+
"instead."
441+
});
433442

434443
// If we restore multi-arg support, remove the `rejects` checks above and un-comment these:
435444
// assert.strictEqual(await env.self.noArgs(), 13);

src/workerd/api/worker-rpc.c++

+15-3
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ JsRpcPromiseAndPipleine callImpl(
467467

468468
auto& ioContext = IoContext::current();
469469

470+
KJ_IF_SOME(lock, ioContext.waitForOutputLocksIfNecessary()) {
471+
// Replace the client with a promise client that will delay thecall until the output gate
472+
// is open.
473+
client = lock.then([client = kj::mv(client)]() mutable { return kj::mv(client); });
474+
}
475+
470476
auto builder = client.callRequest();
471477

472478
// This code here is slightly overcomplicated in order to avoid pushing anything to the
@@ -939,9 +945,9 @@ public:
939945
// object's lifetime is that of the RPC call, but in reality they are refcounted under the
940946
// hood. Since well be executing the call in the JS microtask queue, we have no ability to
941947
// actually cancel execution if a cancellation arrives over RPC, and at the end of that
942-
// execution we're going to accell the call context to write the results. We could invent some
948+
// execution we're going to access the call context to write the results. We could invent some
943949
// complicated way to skip initializing results in the case the call has been canceled, but
944-
// it's easier and safer to just grap a refcount on the call context object itself, which
950+
// it's easier and safer to just grab a refcount on the call context object itself, which
945951
// fully protects us. So... do that.
946952
auto ownCallContext = capnp::CallContextHook::from(callContext).addRef();
947953

@@ -1052,7 +1058,13 @@ public:
10521058
js.throwException(kj::mv(error));
10531059
})));
10541060

1055-
return result;
1061+
if (ctx.hasOutputGate()) {
1062+
return result.then([this]() {
1063+
return KJ_REQUIRE_NONNULL(weakIoContext->tryGet()).waitForOutputLocks();
1064+
});
1065+
} else {
1066+
return result;
1067+
}
10561068
};
10571069

10581070
switch (op.which()) {

0 commit comments

Comments
 (0)