Add finalizer mode

When a type is finalized by V8, it's because it's fallen out of scope. When a
type is finalized by Zig, it's because the Context is being shutdown.

Those are two different environments and might require distinct cleanup logic.
Specifically, a zig-initiated finalization needs to consider that the page and
context are being shutdown. It isn't necessarily safe to execute JavaScript at
this point, and thus, not safe to execute a callback (on_error, on_abort,
ready_state_change, ...).
This commit is contained in:
Karl Seguin
2026-01-22 10:58:28 +08:00
parent d5f26f6d15
commit fc64abee8f
3 changed files with 18 additions and 11 deletions

View File

@@ -371,7 +371,7 @@ fn makeTransfer(self: *Client, req: Request) !*Transfer {
return transfer;
}
fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror) void {
fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror, comptime execute_callback: bool) void {
// this shouldn't happen, we'll crash in debug mode. But in release, we'll
// just noop this state.
if (comptime IS_DEBUG) {
@@ -390,7 +390,9 @@ fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror) void {
});
}
transfer.req.error_callback(transfer.ctx, err);
if (execute_callback) {
transfer.req.error_callback(transfer.ctx, err);
}
}
// Restrictive since it'll only work if there are no inflight requests. In some
@@ -600,7 +602,7 @@ fn processMessages(self: *Client) !bool {
if (!transfer._header_done_called) {
const proceed = transfer.headerDoneCallback(easy) catch |err| {
log.err(.http, "header_done_callback", .{ .err = err });
self.requestFailed(transfer, err);
self.requestFailed(transfer, err, true);
continue;
};
if (!proceed) {
@@ -611,7 +613,7 @@ fn processMessages(self: *Client) !bool {
transfer.req.done_callback(transfer.ctx) catch |err| {
// transfer isn't valid at this point, don't use it.
log.err(.http, "done_callback", .{ .err = err });
self.requestFailed(transfer, err);
self.requestFailed(transfer, err, true);
continue;
};
@@ -622,7 +624,7 @@ fn processMessages(self: *Client) !bool {
}
processed = true;
} else |err| {
self.requestFailed(transfer, err);
self.requestFailed(transfer, err, true);
}
}
return processed;
@@ -972,7 +974,7 @@ pub const Transfer = struct {
}
pub fn abort(self: *Transfer, err: anyerror) void {
self.client.requestFailed(self, err);
self.client.requestFailed(self, err, true);
if (self._handle != null) {
self.client.endTransfer(self);
}
@@ -980,6 +982,7 @@ pub const Transfer = struct {
}
pub fn terminate(self: *Transfer) void {
self.client.requestFailed(self, error.Shutdown, false);
if (self._handle != null) {
self.client.endTransfer(self);
}