Skip to content

Commit

Permalink
Merge pull request #2030 from Warfields/v2
Browse files Browse the repository at this point in the history
Add Exception Details to RPC Exceptions
  • Loading branch information
Warfields committed May 9, 2024
2 parents 74fa082 + d5fe4e4 commit 4979935
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 32 deletions.
19 changes: 19 additions & 0 deletions c++/src/capnp/rpc-test.c++
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,25 @@ KJ_TEST("method throws exception with trace encoder") {
KJ_EXPECT(exception.getRemoteTrace() == "trace for test exception");
}

KJ_TEST("method throws exception with detail") {
TestContext context;

auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF)
.castAs<test::TestMoreStuff>();

kj::Maybe<kj::Exception> maybeException;
client.throwExceptionWithDetailRequest().send().ignoreResult()
.catch_([&](kj::Exception&& e) {
maybeException = kj::mv(e);
}).wait(context.waitScope);

auto exception = KJ_ASSERT_NONNULL(maybeException);
KJ_EXPECT(exception.getDescription() == "remote exception: test exception");
KJ_EXPECT(exception.getRemoteTrace() == nullptr);
auto detail = KJ_ASSERT_NONNULL(exception.getDetail(1));
KJ_EXPECT(kj::str(detail.asChars()) == "foo");
}

KJ_TEST("when OutgoingRpcMessage::send() throws, we don't leak exports") {
// When OutgoingRpcMessage::send() throws an exception on a Call message, we need to clean up
// anything that had been added to the export table as part of the call. At one point this
Expand Down
15 changes: 15 additions & 0 deletions c++/src/capnp/rpc.c++
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ kj::Exception toException(const rpc::Exception::Reader& exception) {
if (exception.hasTrace()) {
result.setRemoteTrace(kj::str(exception.getTrace()));
}
for (auto detail : exception.getDetails()) {
if (detail.hasData()) {
result.setDetail(detail.getDetailId(), kj::heapArray(detail.getData()));
}
}
return result;
}

Expand All @@ -151,6 +156,16 @@ void fromException(const kj::Exception& exception, rpc::Exception::Builder build
builder.setReason(description);
builder.setType(static_cast<rpc::Exception::Type>(exception.getType()));

auto details = exception.getDetails();
if (details.size()) {
auto detailsBuilder = builder.initDetails(details.size());
for (auto i : kj::indices(details)) {
auto out = detailsBuilder[i];
out.setDetailId(details[i].id);
out.setData(details[i].value);
}
}

KJ_IF_SOME(t, traceEncoder) {
builder.setTrace(t(exception));
}
Expand Down
17 changes: 17 additions & 0 deletions c++/src/capnp/rpc.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,23 @@ struct Exception {
# Stack trace text from the remote server. The format is not specified. By default,
# implementations do not provide stack traces; the application must explicitly enable them
# when desired.

details @5 :List(Detail);
# Arbitrary extra information can be added to an exception. Applications can define any kind of
# detail they want. It is expected that exceptions will rarely have more than one or two details.
#
# The main use case for details is to be able to tunnel exceptions of a different type through
# KJ / Cap'n Proto. In particular, Cloudflare Workers commonly has to convert a JavaScript
# exception to KJ and back. The exception is serialized using V8 serialization.

struct Detail {
detailId @0 :UInt64;
# Every type of detail should have a unique ID, which is a 64-bit integer. It's suggested that
# you use `capnp id` to generate these.

data @1 :Data;
# The arbitrary extra information.
}
}

# ========================================================================================
Expand Down
136 changes: 110 additions & 26 deletions c++/src/capnp/rpc.capnp.c++
Original file line number Diff line number Diff line change
Expand Up @@ -1819,63 +1819,73 @@ const ::capnp::_::RawSchema s_d37007fde1f0027d = {
0, 2, i_d37007fde1f0027d, nullptr, nullptr, { &s_d37007fde1f0027d, nullptr, nullptr, 0, 0, nullptr }, true
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<100> b_d625b7063acf691a = {
static const ::capnp::_::AlignedData<122> b_d625b7063acf691a = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
26, 105, 207, 58, 6, 183, 37, 214,
16, 0, 0, 0, 1, 0, 1, 0,
80, 162, 82, 37, 27, 152, 18, 179,
2, 0, 7, 0, 0, 0, 0, 0,
3, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 210, 0, 0, 0,
33, 0, 0, 0, 23, 0, 0, 0,
33, 0, 0, 0, 39, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 0, 0, 31, 1, 0, 0,
53, 0, 0, 0, 87, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 112, 110, 112, 47, 114, 112,
99, 46, 99, 97, 112, 110, 112, 58,
69, 120, 99, 101, 112, 116, 105, 111,
110, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 1, 0, 1, 0,
8, 0, 0, 0, 1, 0, 1, 0,
88, 189, 76, 63, 226, 150, 140, 178,
1, 0, 0, 0, 42, 0, 0, 0,
9, 0, 0, 0, 42, 0, 0, 0,
221, 248, 68, 29, 18, 79, 193, 214,
5, 0, 0, 0, 58, 0, 0, 0,
84, 121, 112, 101, 0, 0, 0, 0,
20, 0, 0, 0, 3, 0, 4, 0,
68, 101, 116, 97, 105, 108, 0, 0,
24, 0, 0, 0, 3, 0, 4, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
125, 0, 0, 0, 58, 0, 0, 0,
153, 0, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
120, 0, 0, 0, 3, 0, 1, 0,
132, 0, 0, 0, 2, 0, 1, 0,
148, 0, 0, 0, 3, 0, 1, 0,
160, 0, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
129, 0, 0, 0, 186, 0, 0, 0,
157, 0, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
132, 0, 0, 0, 3, 0, 1, 0,
144, 0, 0, 0, 2, 0, 1, 0,
160, 0, 0, 0, 3, 0, 1, 0,
172, 0, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
141, 0, 0, 0, 154, 0, 0, 0,
169, 0, 0, 0, 154, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
144, 0, 0, 0, 3, 0, 1, 0,
156, 0, 0, 0, 2, 0, 1, 0,
172, 0, 0, 0, 3, 0, 1, 0,
184, 0, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
153, 0, 0, 0, 42, 0, 0, 0,
181, 0, 0, 0, 42, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
148, 0, 0, 0, 3, 0, 1, 0,
160, 0, 0, 0, 2, 0, 1, 0,
176, 0, 0, 0, 3, 0, 1, 0,
188, 0, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
157, 0, 0, 0, 50, 0, 0, 0,
185, 0, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
180, 0, 0, 0, 3, 0, 1, 0,
192, 0, 0, 0, 2, 0, 1, 0,
5, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
189, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
152, 0, 0, 0, 3, 0, 1, 0,
164, 0, 0, 0, 2, 0, 1, 0,
184, 0, 0, 0, 3, 0, 1, 0,
212, 0, 0, 0, 2, 0, 1, 0,
114, 101, 97, 115, 111, 110, 0, 0,
12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
Expand Down Expand Up @@ -1918,19 +1928,32 @@ static const ::capnp::_::AlignedData<100> b_d625b7063acf691a = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
100, 101, 116, 97, 105, 108, 115, 0,
14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0, 1, 0,
16, 0, 0, 0, 0, 0, 0, 0,
221, 248, 68, 29, 18, 79, 193, 214,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, }
};
::capnp::word const* const bp_d625b7063acf691a = b_d625b7063acf691a.words;
#if !CAPNP_LITE
static const ::capnp::_::RawSchema* const d_d625b7063acf691a[] = {
&s_b28c96e23f4cbd58,
&s_d6c14f121d44f8dd,
};
static const uint16_t m_d625b7063acf691a[] = {2, 1, 0, 4, 3};
static const uint16_t i_d625b7063acf691a[] = {0, 1, 2, 3, 4};
static const uint16_t m_d625b7063acf691a[] = {5, 2, 1, 0, 4, 3};
static const uint16_t i_d625b7063acf691a[] = {0, 1, 2, 3, 4, 5};
const ::capnp::_::RawSchema s_d625b7063acf691a = {
0xd625b7063acf691a, b_d625b7063acf691a.words, 100, d_d625b7063acf691a, m_d625b7063acf691a,
1, 5, i_d625b7063acf691a, nullptr, nullptr, { &s_d625b7063acf691a, nullptr, nullptr, 0, 0, nullptr }, false
0xd625b7063acf691a, b_d625b7063acf691a.words, 122, d_d625b7063acf691a, m_d625b7063acf691a,
2, 6, i_d625b7063acf691a, nullptr, nullptr, { &s_d625b7063acf691a, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<37> b_b28c96e23f4cbd58 = {
Expand Down Expand Up @@ -1980,5 +2003,66 @@ const ::capnp::_::RawSchema s_b28c96e23f4cbd58 = {
0, 4, nullptr, nullptr, nullptr, { &s_b28c96e23f4cbd58, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<50> b_d6c14f121d44f8dd = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
221, 248, 68, 29, 18, 79, 193, 214,
26, 0, 0, 0, 1, 0, 1, 0,
26, 105, 207, 58, 6, 183, 37, 214,
1, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 10, 1, 0, 0,
37, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 0, 0, 119, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 112, 110, 112, 47, 114, 112,
99, 46, 99, 97, 112, 110, 112, 58,
69, 120, 99, 101, 112, 116, 105, 111,
110, 46, 68, 101, 116, 97, 105, 108,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0,
8, 0, 0, 0, 3, 0, 4, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 0, 0, 74, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
40, 0, 0, 0, 3, 0, 1, 0,
52, 0, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 0, 0, 42, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
44, 0, 0, 0, 3, 0, 1, 0,
56, 0, 0, 0, 2, 0, 1, 0,
100, 101, 116, 97, 105, 108, 73, 100,
0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
100, 97, 116, 97, 0, 0, 0, 0,
13, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
13, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, }
};
::capnp::word const* const bp_d6c14f121d44f8dd = b_d6c14f121d44f8dd.words;
#if !CAPNP_LITE
static const uint16_t m_d6c14f121d44f8dd[] = {1, 0};
static const uint16_t i_d6c14f121d44f8dd[] = {0, 1};
const ::capnp::_::RawSchema s_d6c14f121d44f8dd = {
0xd6c14f121d44f8dd, b_d6c14f121d44f8dd.words, 50, nullptr, m_d6c14f121d44f8dd,
0, 2, i_d6c14f121d44f8dd, nullptr, nullptr, { &s_d6c14f121d44f8dd, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
} // namespace schemas
} // namespace capnp

0 comments on commit 4979935

Please sign in to comment.