@requence/service 0.8.3-edge.1191 → 0.8.4-edge.1197
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +79 -0
- package/build/index.js +102 -96
- package/build/index.js.map +3 -3
- package/build/types/service/src/createAmqpConnection.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
# @requence/service
|
|
2
2
|
|
|
3
|
+
## 0.8.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 621b48b: A callback that carries no data is now called with no argument:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
await context.input.mail.delete();
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The `null` it used to need was never the caller's to write. It is how the
|
|
14
|
+
**output schema** spells "this position carries nothing": `RequenceCallback<void>`
|
|
15
|
+
compiles to nothing typescript-json-schema has a root type for, and
|
|
16
|
+
`RequenceCallback<undefined>` compiles but silently drops the `callback` marker
|
|
17
|
+
along with the argument — so `RequenceCallback<null>` is the only declaration
|
|
18
|
+
available, and every call site paid for that. A callback that does carry data is
|
|
19
|
+
untouched, and a forgotten argument is still an error.
|
|
20
|
+
|
|
21
|
+
`RequenceCallback<T>` makes the argument optional exactly when `null extends T`,
|
|
22
|
+
through a conditional **tuple**: a conditional on the parameter type alone cannot
|
|
23
|
+
change the ARITY, and the arity is the whole point. Writing the `null` out still
|
|
24
|
+
works and still means the same thing.
|
|
25
|
+
|
|
26
|
+
Optionality at the call site is not enough by itself. The operator validates
|
|
27
|
+
every invocation against the callback's declared argument schema, which for this
|
|
28
|
+
kind of callback is `{ type: 'null' }` — so both reconstruction sites, the
|
|
29
|
+
`deserialize` in `@requence/callbacks` and its Python mirror, default an omitted
|
|
30
|
+
argument to `null` rather than letting `undefined` reach the wire. That default
|
|
31
|
+
is unconditional: a boundary holds a reference, never the emitting node's output
|
|
32
|
+
schema, and a callback that DOES declare data fails the same validation either
|
|
33
|
+
way — turning `undefined` into `null` there only changes which of the two it is
|
|
34
|
+
refused as.
|
|
35
|
+
|
|
36
|
+
The declaration is written out four times — `@requence/helpers` for both SDKs,
|
|
37
|
+
`RequenceTypes.ts` for the logic-node editor, and the two assignability
|
|
38
|
+
harnesses. The fifth copy, in `createJsonSchema.ts`, is deliberately an object
|
|
39
|
+
shape with no call signature and does not move with them. The editor's copy is
|
|
40
|
+
now asserted through the real language service, since it is the one that decides
|
|
41
|
+
whether a script compiles.
|
|
42
|
+
|
|
43
|
+
- f71e500: A durable callback that could not be run is now reported on the node that emitted
|
|
44
|
+
it, instead of only in one service process's log.
|
|
45
|
+
|
|
46
|
+
Two things can go wrong once an invocation has been consumed: the deployed version
|
|
47
|
+
no longer declares the name, or the handler throws. Both were logged by the service
|
|
48
|
+
and acked — a requeue would rerun a side-effecting callback forever — and that log
|
|
49
|
+
is nowhere a template author looks. Combined with imapflow's `messageDelete`
|
|
50
|
+
returning `true` when the _server_ accepted the command rather than when it matched
|
|
51
|
+
a mail, a failed `mail.delete()` was indistinguishable from a delete that did
|
|
52
|
+
nothing. That silence is what made the stale computed-configuration bug beside it
|
|
53
|
+
cost an afternoon.
|
|
54
|
+
|
|
55
|
+
The counterpart already existed for an invocation **nobody consumed**
|
|
56
|
+
(`DURABLE_CALLBACK_INVOCATION_HEADER`, reported by the operator off the returned
|
|
57
|
+
copy). This is the other half, and only the consuming instance can see it, so both
|
|
58
|
+
SDKs publish it: `DURABLE_CALLBACK_ERROR_HEADER`, carrying the emitting node, the
|
|
59
|
+
declaration name and the error's **message** — not its stack, which belongs in the
|
|
60
|
+
service's log — cut at 500 characters at the source as well as in the update
|
|
61
|
+
schema.
|
|
62
|
+
|
|
63
|
+
It rides the ordinary result exchange with **no correlation id and no index**,
|
|
64
|
+
exactly like a surface interaction failure and a resume announcement: the handler
|
|
65
|
+
ran for no dispatch, so it has no message to be a result FOR, and every other arm
|
|
66
|
+
of the result path would have failed the emitting node for a callback the graph
|
|
67
|
+
chose to call.
|
|
68
|
+
|
|
69
|
+
The operator turns it into a `NODE_DEBUG` on that node — `severity: 'system'`
|
|
70
|
+
because the operator is speaking, `event: null` because nothing was re-sent and no
|
|
71
|
+
run ended. The node lookup, the "nowhere to report" arm and the update's shape are
|
|
72
|
+
shared with the undelivered path through one `reportCallbackOnNode`, since only the
|
|
73
|
+
sentence differs. Every failure of that lookup stays "nowhere to report": a run can
|
|
74
|
+
end while an invocation of it is still in flight, and a throw escaping there nacks a
|
|
75
|
+
delivery at the head of a single-active-consumer FIFO queue, where it wedges every
|
|
76
|
+
task on that shard.
|
|
77
|
+
|
|
78
|
+
**This makes a failure visible, not catchable.** The graph called the callback and
|
|
79
|
+
moved on long before the handler ran, so there is no call site left to throw at. A
|
|
80
|
+
callback is still `(arg) => void` in the call direction.
|
|
81
|
+
|
|
3
82
|
## 0.8.2
|
|
4
83
|
|
|
5
84
|
### Patch Changes
|
package/build/index.js
CHANGED
|
@@ -2008,7 +2008,7 @@ function createConnection({
|
|
|
2008
2008
|
clientProperties: {
|
|
2009
2009
|
...connectionOptions?.clientProperties,
|
|
2010
2010
|
...buildServiceClientProperties({
|
|
2011
|
-
libVersion: "javascript@0.8.
|
|
2011
|
+
libVersion: "javascript@0.8.4-edge.1197",
|
|
2012
2012
|
serviceVersion: version,
|
|
2013
2013
|
connectionId,
|
|
2014
2014
|
prefetch,
|
|
@@ -2569,7 +2569,7 @@ function createConnection({
|
|
|
2569
2569
|
begin: true,
|
|
2570
2570
|
epoch,
|
|
2571
2571
|
...buildServiceIdentityHeaders({
|
|
2572
|
-
libVersion: "javascript@0.8.
|
|
2572
|
+
libVersion: "javascript@0.8.4-edge.1197",
|
|
2573
2573
|
name,
|
|
2574
2574
|
holdsSlot: !(isGeneratorHandler && mode === "CONTINUOUS")
|
|
2575
2575
|
})
|
|
@@ -2805,107 +2805,113 @@ function createConnection({
|
|
|
2805
2805
|
throw new Error("a defer key can only be used once");
|
|
2806
2806
|
}
|
|
2807
2807
|
activeMessageKeys.add(messageKey);
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
const
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2808
|
+
try {
|
|
2809
|
+
let publishIndex = 0;
|
|
2810
|
+
const { taskId, messageId, ...options } = messageKeySchema.parse(messageKey);
|
|
2811
|
+
const activeMessage = async () => {
|
|
2812
|
+
if (activeMessages.has(messageId)) {
|
|
2813
|
+
await activeMessages.get(messageId);
|
|
2814
|
+
}
|
|
2815
|
+
};
|
|
2816
|
+
const registeredCallbackIds = new Set;
|
|
2817
|
+
const outbound = createOutboundBoundary(options);
|
|
2818
|
+
const growth = callbackGrowth.forDelivery({ taskId });
|
|
2819
|
+
const registerCallback = (callback, path2) => {
|
|
2820
|
+
const callbackId = crypto.randomUUID();
|
|
2821
|
+
registeredCallbackIds.add(callbackId);
|
|
2822
|
+
callbacks.set(callbackId, {
|
|
2823
|
+
callback,
|
|
2824
|
+
onCallbackInvoke: dispatchInvocation
|
|
2825
|
+
});
|
|
2826
|
+
growth.record(path2);
|
|
2827
|
+
return { sourceId: connectionId, callbackId };
|
|
2828
|
+
};
|
|
2829
|
+
const dispatchInvocation = (invocation) => {
|
|
2830
|
+
outbound.track(outbound.send(invocation.arg, {
|
|
2831
|
+
outputName: invocation.outputName,
|
|
2832
|
+
onCallback: registerCallback
|
|
2833
|
+
}).then((data) => publish({
|
|
2834
|
+
index: 0,
|
|
2835
|
+
version,
|
|
2836
|
+
taskId,
|
|
2837
|
+
messageId,
|
|
2838
|
+
data: invocationPayload(invocation, data),
|
|
2839
|
+
outputName: invocation.outputName,
|
|
2840
|
+
propertyPath: invocation.propertyPath,
|
|
2841
|
+
...invocationHeaders(invocation, options.nodeId)
|
|
2842
|
+
})));
|
|
2843
|
+
};
|
|
2844
|
+
const publishDeps = {
|
|
2845
|
+
outbound,
|
|
2846
|
+
registerCallback,
|
|
2835
2847
|
taskId,
|
|
2836
2848
|
messageId,
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2849
|
+
nextIndex: () => publishIndex++,
|
|
2850
|
+
gate: activeMessage
|
|
2851
|
+
};
|
|
2852
|
+
const renderSurface = buildRender(publishDeps);
|
|
2853
|
+
const sendApi = {
|
|
2854
|
+
...buildSendApi(publishDeps),
|
|
2855
|
+
render(ui, props, renderOptions) {
|
|
2856
|
+
renderSurface({
|
|
2857
|
+
ui,
|
|
2858
|
+
props,
|
|
2859
|
+
surfaceId: renderOptions?.surfaceId ?? DEFAULT_SURFACE_ID
|
|
2860
|
+
});
|
|
2861
|
+
},
|
|
2862
|
+
async abort(error) {
|
|
2863
|
+
await activeMessage();
|
|
2864
|
+
channelWrapper.publish(`${exchange}-retry`, "operator", error instanceof Error ? error.message : error, {
|
|
2865
|
+
persistent: true,
|
|
2866
|
+
correlationId: messageId,
|
|
2867
|
+
expiration: 0,
|
|
2868
|
+
priority: 0,
|
|
2869
|
+
contentType: "text/plain",
|
|
2870
|
+
headers: {
|
|
2871
|
+
taskId,
|
|
2872
|
+
index: publishIndex++,
|
|
2873
|
+
abort: true
|
|
2874
|
+
}
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
};
|
|
2878
|
+
announceResume({ taskId, messageId });
|
|
2879
|
+
try {
|
|
2880
|
+
const result = await actor(sendApi);
|
|
2881
|
+
if (result != null && typeof result === "object" && ((Symbol.asyncIterator in result) || (Symbol.iterator in result))) {
|
|
2882
|
+
const iterable = result;
|
|
2883
|
+
for await (const value of iterable) {
|
|
2884
|
+
if (value !== undefined) {
|
|
2885
|
+
await sendApi.send(value);
|
|
2886
|
+
}
|
|
2873
2887
|
}
|
|
2874
|
-
})
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2888
|
+
} else if (result !== undefined) {
|
|
2889
|
+
await sendApi.send(result);
|
|
2890
|
+
}
|
|
2891
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
2892
|
+
await activeMessage();
|
|
2893
|
+
await outbound.settle();
|
|
2894
|
+
} catch (error) {
|
|
2895
|
+
registeredCallbackIds.forEach((id) => callbacks.delete(id));
|
|
2896
|
+
const first = error instanceof AggregateError && error.errors[0] instanceof Error ? error.errors[0] : error instanceof Error ? error : new Error(String(error));
|
|
2897
|
+
try {
|
|
2898
|
+
await sendApi.abort(first);
|
|
2899
|
+
} catch (abortError) {
|
|
2900
|
+
simple_default.error("Requence act() could not report its failure to the operator:", abortError);
|
|
2884
2901
|
}
|
|
2902
|
+
throw error;
|
|
2885
2903
|
}
|
|
2886
|
-
} else if (result !== undefined) {
|
|
2887
|
-
await sendApi.send(result);
|
|
2888
|
-
}
|
|
2889
|
-
await new Promise((resolve2) => setImmediate(resolve2));
|
|
2890
|
-
await activeMessage();
|
|
2891
|
-
try {
|
|
2892
|
-
await outbound.settle();
|
|
2893
|
-
} catch (error) {
|
|
2894
2904
|
registeredCallbackIds.forEach((id) => callbacks.delete(id));
|
|
2895
|
-
|
|
2896
|
-
|
|
2905
|
+
await publish({
|
|
2906
|
+
index: publishIndex++,
|
|
2907
|
+
version,
|
|
2908
|
+
messageId,
|
|
2909
|
+
taskId,
|
|
2910
|
+
done: true
|
|
2911
|
+
});
|
|
2912
|
+
} finally {
|
|
2897
2913
|
activeMessageKeys.delete(messageKey);
|
|
2898
|
-
throw error;
|
|
2899
2914
|
}
|
|
2900
|
-
registeredCallbackIds.forEach((id) => callbacks.delete(id));
|
|
2901
|
-
await publish({
|
|
2902
|
-
index: publishIndex++,
|
|
2903
|
-
version,
|
|
2904
|
-
messageId,
|
|
2905
|
-
taskId,
|
|
2906
|
-
done: true
|
|
2907
|
-
});
|
|
2908
|
-
activeMessageKeys.delete(messageKey);
|
|
2909
2915
|
}
|
|
2910
2916
|
};
|
|
2911
2917
|
return api;
|
|
@@ -3140,5 +3146,5 @@ export {
|
|
|
3140
3146
|
PayloadTooLargeError
|
|
3141
3147
|
};
|
|
3142
3148
|
|
|
3143
|
-
//# debugId=
|
|
3149
|
+
//# debugId=59535360ADC9F22B64756E2164756E21
|
|
3144
3150
|
//# sourceMappingURL=index.js.map
|