effect 4.0.4 → 4.0.5
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/ai-docs/src/52_graphql/10_basics.ts +19 -13
- package/ai-docs/src/52_graphql/30_batching.ts +6 -4
- package/ai-docs/src/52_graphql/40_aliased-batching.ts +6 -4
- package/dist/Array.d.ts +90 -6
- package/dist/Array.d.ts.map +1 -1
- package/dist/Array.js +4 -2
- package/dist/Array.js.map +1 -1
- package/dist/Channel.d.ts +6 -1
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +17 -3
- package/dist/Channel.js.map +1 -1
- package/dist/ConfigProvider.d.ts.map +1 -1
- package/dist/ConfigProvider.js +33 -32
- package/dist/ConfigProvider.js.map +1 -1
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +2 -5
- package/dist/Duration.js.map +1 -1
- package/dist/Effect.d.ts +61 -19
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +58 -39
- package/dist/Effect.js.map +1 -1
- package/dist/FileSystem.d.ts +23 -9
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/Match.d.ts +20 -6
- package/dist/Match.d.ts.map +1 -1
- package/dist/Match.js +2 -2
- package/dist/Match.js.map +1 -1
- package/dist/Path.d.ts +37 -5
- package/dist/Path.d.ts.map +1 -1
- package/dist/Path.js +36 -5
- package/dist/Path.js.map +1 -1
- package/dist/Schema.d.ts +7 -2
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +9 -2
- package/dist/Schema.js.map +1 -1
- package/dist/String.d.ts +12 -0
- package/dist/String.d.ts.map +1 -1
- package/dist/String.js +17 -4
- package/dist/String.js.map +1 -1
- package/dist/TxRef.d.ts.map +1 -1
- package/dist/TxRef.js +3 -2
- package/dist/TxRef.js.map +1 -1
- package/dist/ai/AiError.d.ts +10 -10
- package/dist/ai/AiError.d.ts.map +1 -1
- package/dist/ai/AiError.js +1 -1
- package/dist/ai/AiError.js.map +1 -1
- package/dist/ai/Decision.d.ts +70 -19
- package/dist/ai/Decision.d.ts.map +1 -1
- package/dist/ai/Decision.js +37 -3
- package/dist/ai/Decision.js.map +1 -1
- package/dist/ai/DecisionModel.js +1 -1
- package/dist/ai/DecisionModel.js.map +1 -1
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +47 -35
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpServer.d.ts +6 -52
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +2 -28
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Response.d.ts +1 -1
- package/dist/cli/Completions.d.ts +5 -0
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/Flag.d.ts +100 -0
- package/dist/cli/Flag.d.ts.map +1 -1
- package/dist/cli/Flag.js +33 -0
- package/dist/cli/Flag.js.map +1 -1
- package/dist/cli/Param.d.ts +87 -0
- package/dist/cli/Param.d.ts.map +1 -1
- package/dist/cli/Param.js +30 -0
- package/dist/cli/Param.js.map +1 -1
- package/dist/cli/internal/command.d.ts.map +1 -1
- package/dist/cli/internal/command.js +2 -1
- package/dist/cli/internal/command.js.map +1 -1
- package/dist/cli/internal/completions/bash.js +4 -3
- package/dist/cli/internal/completions/bash.js.map +1 -1
- package/dist/cli/internal/completions/descriptor.js +8 -1
- package/dist/cli/internal/completions/descriptor.js.map +1 -1
- package/dist/cli/internal/completions/fish.js +4 -4
- package/dist/cli/internal/completions/fish.js.map +1 -1
- package/dist/cli/internal/completions/powershell.js +3 -2
- package/dist/cli/internal/completions/powershell.js.map +1 -1
- package/dist/cli/internal/completions/zsh.js +7 -3
- package/dist/cli/internal/completions/zsh.js.map +1 -1
- package/dist/cli/internal/parser.js +11 -3
- package/dist/cli/internal/parser.js.map +1 -1
- package/dist/cli/internal/wizard.d.ts.map +1 -1
- package/dist/cli/internal/wizard.js +2 -1
- package/dist/cli/internal/wizard.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts +1 -0
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +67 -13
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +20 -12
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +54 -34
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +1 -1
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/encoding/Sse.js +1 -1
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/graphql/GraphQLClient.d.ts.map +1 -1
- package/dist/graphql/GraphQLClient.js +12 -5
- package/dist/graphql/GraphQLClient.js.map +1 -1
- package/dist/graphql/GraphQLProtocol.d.ts +249 -11
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
- package/dist/graphql/GraphQLProtocol.js +98 -8
- package/dist/graphql/GraphQLProtocol.js.map +1 -1
- package/dist/graphql/GraphQLResolver.d.ts +1 -1
- package/dist/graphql/GraphQLResolver.d.ts.map +1 -1
- package/dist/graphql/GraphQLResolver.js +46 -16
- package/dist/graphql/GraphQLResolver.js.map +1 -1
- package/dist/http/FetchHttpClient.d.ts +6 -3
- package/dist/http/FetchHttpClient.d.ts.map +1 -1
- package/dist/http/FetchHttpClient.js +6 -3
- package/dist/http/FetchHttpClient.js.map +1 -1
- package/dist/http/FindMyWay/internal/router.js +2 -1
- package/dist/http/FindMyWay/internal/router.js.map +1 -1
- package/dist/http/Headers.d.ts +3 -3
- package/dist/http/Headers.d.ts.map +1 -1
- package/dist/http/Headers.js +6 -5
- package/dist/http/Headers.js.map +1 -1
- package/dist/http/HttpClient.d.ts +12 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +14 -1
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpClientError.d.ts.map +1 -1
- package/dist/http/HttpClientError.js +8 -6
- package/dist/http/HttpClientError.js.map +1 -1
- package/dist/http/HttpClientRequest.d.ts +147 -4
- package/dist/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/http/HttpClientRequest.js +47 -1
- package/dist/http/HttpClientRequest.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts +60 -0
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +67 -5
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +52 -13
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerError.d.ts.map +1 -1
- package/dist/http/HttpServerError.js +6 -4
- package/dist/http/HttpServerError.js.map +1 -1
- package/dist/http/HttpServerRequest.js +2 -2
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/HttpStaticServer.d.ts.map +1 -1
- package/dist/http/HttpStaticServer.js +4 -10
- package/dist/http/HttpStaticServer.js.map +1 -1
- package/dist/http/HttpTraceContext.js +1 -1
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http/Url.d.ts.map +1 -1
- package/dist/http/Url.js +2 -1
- package/dist/http/Url.js.map +1 -1
- package/dist/http/UrlParams.d.ts +112 -8
- package/dist/http/UrlParams.d.ts.map +1 -1
- package/dist/http/UrlParams.js +141 -14
- package/dist/http/UrlParams.js.map +1 -1
- package/dist/http/internal/compression.d.ts +1 -1
- package/dist/http/internal/compression.d.ts.map +1 -1
- package/dist/http/internal/compression.js +2 -10
- package/dist/http/internal/compression.js.map +1 -1
- package/dist/http/internal/compressionBody.d.ts +2 -0
- package/dist/http/internal/compressionBody.d.ts.map +1 -0
- package/dist/http/internal/compressionBody.js +36 -0
- package/dist/http/internal/compressionBody.js.map +1 -0
- package/dist/http/internal/decompression.d.ts +2 -0
- package/dist/http/internal/decompression.d.ts.map +1 -0
- package/dist/http/internal/decompression.js +162 -0
- package/dist/http/internal/decompression.js.map +1 -0
- package/dist/http/internal/tracing.js +14 -4
- package/dist/http/internal/tracing.js.map +1 -1
- package/dist/http/internal/urlParams.d.ts +2 -0
- package/dist/http/internal/urlParams.d.ts.map +1 -0
- package/dist/http/internal/urlParams.js +4 -0
- package/dist/http/internal/urlParams.js.map +1 -0
- package/dist/http-api/HttpApiClient.d.ts.map +1 -1
- package/dist/http-api/HttpApiClient.js +2 -1
- package/dist/http-api/HttpApiClient.js.map +1 -1
- package/dist/internal/core.js +17 -1
- package/dist/internal/core.js.map +1 -1
- package/dist/internal/effect.js +5 -3
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/graphql.js +12 -2
- package/dist/internal/graphql.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/observability/Otlp.d.ts +15 -0
- package/dist/observability/Otlp.d.ts.map +1 -1
- package/dist/observability/Otlp.js +3 -0
- package/dist/observability/Otlp.js.map +1 -1
- package/dist/observability/OtlpExporter.d.ts +8 -0
- package/dist/observability/OtlpExporter.d.ts.map +1 -1
- package/dist/observability/OtlpExporter.js +10 -1
- package/dist/observability/OtlpExporter.js.map +1 -1
- package/dist/observability/OtlpLogger.d.ts +17 -0
- package/dist/observability/OtlpLogger.d.ts.map +1 -1
- package/dist/observability/OtlpLogger.js +14 -1
- package/dist/observability/OtlpLogger.js.map +1 -1
- package/dist/observability/OtlpMetrics.d.ts +17 -0
- package/dist/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/observability/OtlpMetrics.js +13 -0
- package/dist/observability/OtlpMetrics.js.map +1 -1
- package/dist/observability/OtlpTracer.d.ts +17 -0
- package/dist/observability/OtlpTracer.d.ts.map +1 -1
- package/dist/observability/OtlpTracer.js +15 -2
- package/dist/observability/OtlpTracer.js.map +1 -1
- package/dist/reactivity/AsyncResult.d.ts +6 -0
- package/dist/reactivity/AsyncResult.d.ts.map +1 -1
- package/dist/reactivity/AsyncResult.js +27 -0
- package/dist/reactivity/AsyncResult.js.map +1 -1
- package/dist/reactivity/AtomRegistry.js +3 -1
- package/dist/reactivity/AtomRegistry.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +6 -1
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +8 -7
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +8 -7
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/testing/TestClock.d.ts +16 -3
- package/dist/testing/TestClock.d.ts.map +1 -1
- package/dist/testing/TestClock.js +112 -22
- package/dist/testing/TestClock.js.map +1 -1
- package/dist/workflow/Activity.js +1 -0
- package/dist/workflow/Activity.js.map +1 -1
- package/dist/workflow/Workflow.d.ts +22 -0
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js +15 -3
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +20 -1
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +35 -21
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +1 -1
- package/src/Array.ts +95 -6
- package/src/Channel.ts +24 -3
- package/src/ConfigProvider.ts +40 -44
- package/src/Duration.ts +4 -5
- package/src/Effect.ts +140 -53
- package/src/FileSystem.ts +23 -9
- package/src/Match.ts +65 -12
- package/src/Path.ts +52 -7
- package/src/Schema.ts +17 -4
- package/src/String.ts +17 -4
- package/src/TxRef.ts +4 -2
- package/src/ai/AiError.ts +3 -1
- package/src/ai/Decision.ts +70 -21
- package/src/ai/DecisionModel.ts +1 -1
- package/src/ai/LanguageModel.ts +57 -51
- package/src/ai/McpServer.ts +15 -55
- package/src/cli/Completions.ts +5 -0
- package/src/cli/Flag.ts +101 -0
- package/src/cli/Param.ts +96 -0
- package/src/cli/internal/command.ts +2 -1
- package/src/cli/internal/completions/bash.ts +4 -3
- package/src/cli/internal/completions/descriptor.ts +10 -1
- package/src/cli/internal/completions/fish.ts +4 -4
- package/src/cli/internal/completions/powershell.ts +5 -2
- package/src/cli/internal/completions/zsh.ts +7 -3
- package/src/cli/internal/parser.ts +12 -3
- package/src/cli/internal/wizard.ts +2 -1
- package/src/cluster/ClusterWorkflowEngine.ts +92 -24
- package/src/cluster/MessageStorage.ts +14 -3
- package/src/cluster/Runners.ts +88 -66
- package/src/cluster/internal/entityManager.ts +1 -1
- package/src/encoding/Sse.ts +1 -1
- package/src/graphql/GraphQLClient.ts +17 -5
- package/src/graphql/GraphQLProtocol.ts +274 -20
- package/src/graphql/GraphQLResolver.ts +45 -17
- package/src/http/FetchHttpClient.ts +6 -3
- package/src/http/FindMyWay/internal/router.ts +2 -1
- package/src/http/Headers.ts +6 -9
- package/src/http/HttpClient.ts +18 -1
- package/src/http/HttpClientError.ts +10 -6
- package/src/http/HttpClientRequest.ts +173 -7
- package/src/http/HttpMiddleware.ts +85 -5
- package/src/http/HttpRouter.ts +60 -13
- package/src/http/HttpServerError.ts +8 -4
- package/src/http/HttpServerRequest.ts +2 -2
- package/src/http/HttpStaticServer.ts +4 -10
- package/src/http/HttpTraceContext.ts +1 -1
- package/src/http/Url.ts +2 -1
- package/src/http/UrlParams.ts +225 -26
- package/src/http/internal/compression.ts +3 -17
- package/src/http/internal/compressionBody.ts +56 -0
- package/src/http/internal/decompression.ts +226 -0
- package/src/http/internal/tracing.ts +21 -4
- package/src/http/internal/urlParams.ts +5 -0
- package/src/http-api/HttpApiClient.ts +2 -1
- package/src/internal/core.ts +21 -1
- package/src/internal/effect.ts +5 -4
- package/src/internal/graphql.ts +30 -7
- package/src/internal/version.ts +1 -1
- package/src/observability/Otlp.ts +18 -0
- package/src/observability/OtlpExporter.ts +14 -3
- package/src/observability/OtlpLogger.ts +31 -2
- package/src/observability/OtlpMetrics.ts +30 -1
- package/src/observability/OtlpTracer.ts +32 -3
- package/src/reactivity/AsyncResult.ts +31 -0
- package/src/reactivity/AtomRegistry.ts +3 -1
- package/src/rpc/RpcClient.ts +6 -1
- package/src/sql/SqlClient.ts +9 -7
- package/src/testing/TestClock.ts +144 -29
- package/src/workflow/Activity.ts +1 -0
- package/src/workflow/Workflow.ts +31 -5
- package/src/workflow/WorkflowEngine.ts +60 -22
|
@@ -55,6 +55,11 @@ export const make: (
|
|
|
55
55
|
readonly attributes?: Record<string, unknown>
|
|
56
56
|
} | undefined
|
|
57
57
|
readonly headers?: Headers.Input | undefined
|
|
58
|
+
/**
|
|
59
|
+
* Request compression. Defaults to "none". Gzip uses
|
|
60
|
+
* HttpClientRequest's default minimum body size of 1KB.
|
|
61
|
+
*/
|
|
62
|
+
readonly compression?: "gzip" | "none" | undefined
|
|
58
63
|
readonly exportInterval?: Duration.Input | undefined
|
|
59
64
|
readonly maxBatchSize?: number | undefined
|
|
60
65
|
readonly context?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
|
|
@@ -76,6 +81,7 @@ export const make: (
|
|
|
76
81
|
label: "OtlpTracer",
|
|
77
82
|
url: options.url,
|
|
78
83
|
headers: options.headers,
|
|
84
|
+
compression: options.compression,
|
|
79
85
|
exportInterval: options.exportInterval ?? Duration.seconds(5),
|
|
80
86
|
maxBatchSize: options.maxBatchSize ?? 1000,
|
|
81
87
|
body(spans) {
|
|
@@ -128,6 +134,11 @@ export const layer: (options: {
|
|
|
128
134
|
readonly attributes?: Record<string, unknown>
|
|
129
135
|
} | undefined
|
|
130
136
|
readonly headers?: Headers.Input | undefined
|
|
137
|
+
/**
|
|
138
|
+
* Request compression. Defaults to "none". Gzip uses
|
|
139
|
+
* HttpClientRequest's default minimum body size of 1KB.
|
|
140
|
+
*/
|
|
141
|
+
readonly compression?: "gzip" | "none" | undefined
|
|
131
142
|
readonly exportInterval?: Duration.Input | undefined
|
|
132
143
|
readonly maxBatchSize?: number | undefined
|
|
133
144
|
readonly context?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
|
|
@@ -141,6 +152,13 @@ export const layer: (options: {
|
|
|
141
152
|
/**
|
|
142
153
|
* Creates an OTLP traces layer from OpenTelemetry configuration.
|
|
143
154
|
*
|
|
155
|
+
* **Details**
|
|
156
|
+
*
|
|
157
|
+
* Compression accepts "gzip" or "none".
|
|
158
|
+
* `OTEL_EXPORTER_OTLP_TRACES_COMPRESSION` takes precedence over
|
|
159
|
+
* `OTEL_EXPORTER_OTLP_COMPRESSION`, defaulting to "none". Gzip uses
|
|
160
|
+
* HttpClientRequest's default minimum body size of 1KB.
|
|
161
|
+
*
|
|
144
162
|
* @stability unstable
|
|
145
163
|
* @category layers
|
|
146
164
|
* @since 4.0.0
|
|
@@ -165,7 +183,17 @@ export const layerFromConfig = (options?: {
|
|
|
165
183
|
return Exporter.layerFlusher
|
|
166
184
|
}
|
|
167
185
|
|
|
168
|
-
const {
|
|
186
|
+
const {
|
|
187
|
+
baseCompression,
|
|
188
|
+
compression,
|
|
189
|
+
baseTimeout,
|
|
190
|
+
tracesTimeout,
|
|
191
|
+
exportTimeout,
|
|
192
|
+
scheduleDelay,
|
|
193
|
+
maxBatchSize
|
|
194
|
+
} = yield* Config.all({
|
|
195
|
+
baseCompression: Config.option(Config.Literals(["gzip", "none"], "OTEL_EXPORTER_OTLP_COMPRESSION")),
|
|
196
|
+
compression: Config.option(Config.Literals(["gzip", "none"], "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION")),
|
|
169
197
|
baseTimeout: Config.option(Config.Int("OTEL_EXPORTER_OTLP_TIMEOUT")),
|
|
170
198
|
tracesTimeout: Config.option(Config.Int("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT")),
|
|
171
199
|
exportTimeout: Config.option(Config.Int("OTEL_BSP_EXPORT_TIMEOUT")),
|
|
@@ -185,6 +213,7 @@ export const layerFromConfig = (options?: {
|
|
|
185
213
|
url: endpoint.toString(),
|
|
186
214
|
resource: options?.resource,
|
|
187
215
|
headers: options?.headers ?? (yield* OtlpEnv.headers("TRACES")),
|
|
216
|
+
compression: Option.getOrElse(Option.firstSomeOf([compression, baseCompression]), () => "none" as const),
|
|
188
217
|
exportInterval: Option.getOrUndefined(scheduleDelay),
|
|
189
218
|
maxBatchSize: Option.getOrUndefined(maxBatchSize),
|
|
190
219
|
context: options?.context,
|
|
@@ -342,7 +371,7 @@ const makeOtlpSpan = (self: SpanImpl): OtlpSpan => {
|
|
|
342
371
|
for (let i = 0; i < self.links.length; i++) {
|
|
343
372
|
const link = self.links[i]
|
|
344
373
|
links.push({
|
|
345
|
-
traceId: link.span.traceId,
|
|
374
|
+
traceId: link.span.traceId.padStart(32, "0"),
|
|
346
375
|
spanId: link.span.spanId,
|
|
347
376
|
attributes: entriesToAttributes(Object.entries(link.attributes)),
|
|
348
377
|
droppedAttributesCount: 0
|
|
@@ -350,7 +379,7 @@ const makeOtlpSpan = (self: SpanImpl): OtlpSpan => {
|
|
|
350
379
|
}
|
|
351
380
|
|
|
352
381
|
return {
|
|
353
|
-
traceId: self.traceId,
|
|
382
|
+
traceId: self.traceId.padStart(32, "0"),
|
|
354
383
|
spanId: self.spanId,
|
|
355
384
|
parentSpanId: Option.isSome(self.parent) ? self.parent.value.spanId : undefined,
|
|
356
385
|
name: self.name,
|
|
@@ -901,6 +901,12 @@ export const matchWithWaiting: {
|
|
|
901
901
|
/**
|
|
902
902
|
* Combines an iterable or record of `AsyncResult` and plain values into one `AsyncResult`, returning the first non-success result or a success of the collected values marked waiting when any input success is waiting.
|
|
903
903
|
*
|
|
904
|
+
* **Details**
|
|
905
|
+
*
|
|
906
|
+
* If the first non-success result is a failure, its previous success is
|
|
907
|
+
* rebuilt in the combined shape from each input's current or previous value.
|
|
908
|
+
* It is omitted if any input has no value.
|
|
909
|
+
*
|
|
904
910
|
* @stability unstable
|
|
905
911
|
* @category combinators
|
|
906
912
|
* @since 4.0.0
|
|
@@ -932,6 +938,11 @@ export const all = <const Arg extends Iterable<any> | Record<string, any>>(
|
|
|
932
938
|
if (!isAsyncResult(result)) {
|
|
933
939
|
InternalRecord.assignProperty(successes, key, result)
|
|
934
940
|
continue
|
|
941
|
+
} else if (isFailure(result)) {
|
|
942
|
+
return failure(result.cause, {
|
|
943
|
+
previousSuccess: combinedPreviousSuccess(entries, isIter),
|
|
944
|
+
waiting: result.waiting
|
|
945
|
+
}) as any
|
|
935
946
|
} else if (!isSuccess(result)) {
|
|
936
947
|
return result as any
|
|
937
948
|
}
|
|
@@ -943,6 +954,26 @@ export const all = <const Arg extends Iterable<any> | Record<string, any>>(
|
|
|
943
954
|
return success(successes, { waiting }) as any
|
|
944
955
|
}
|
|
945
956
|
|
|
957
|
+
const combinedPreviousSuccess = (
|
|
958
|
+
entries: ReadonlyArray<readonly [PropertyKey, unknown]>,
|
|
959
|
+
isIter: boolean
|
|
960
|
+
): Option.Option<Success<unknown, never>> => {
|
|
961
|
+
const values: any = isIter ? [] : {}
|
|
962
|
+
for (let i = 0; i < entries.length; i++) {
|
|
963
|
+
const [key, entry] = entries[i]
|
|
964
|
+
if (!isAsyncResult(entry)) {
|
|
965
|
+
InternalRecord.assignProperty(values, key, entry)
|
|
966
|
+
continue
|
|
967
|
+
}
|
|
968
|
+
const entryValue = value(entry)
|
|
969
|
+
if (Option.isNone(entryValue)) {
|
|
970
|
+
return Option.none()
|
|
971
|
+
}
|
|
972
|
+
InternalRecord.assignProperty(values, key, entryValue.value)
|
|
973
|
+
}
|
|
974
|
+
return Option.some(success(values))
|
|
975
|
+
}
|
|
976
|
+
|
|
946
977
|
/**
|
|
947
978
|
* Creates a typed builder for rendering an `AsyncResult` by handling waiting, initial, success, error, defect, interrupt, and failure cases.
|
|
948
979
|
*
|
|
@@ -967,7 +967,9 @@ class NodeImpl<A> {
|
|
|
967
967
|
this._value = value
|
|
968
968
|
let failure: unknown = noFailure
|
|
969
969
|
try {
|
|
970
|
-
|
|
970
|
+
// A first value cannot replace one held by a dependent. Recovery still
|
|
971
|
+
// retries dependents whose reads failed before this node had a value.
|
|
972
|
+
if (initialized || recovered) this.invalidateChildren()
|
|
971
973
|
} catch (error) {
|
|
972
974
|
failure = error
|
|
973
975
|
}
|
package/src/rpc/RpcClient.ts
CHANGED
|
@@ -1249,16 +1249,21 @@ const makePinger = Effect.fnUntraced(function*<A, E, R>(writePing: Effect.Effect
|
|
|
1249
1249
|
const interval = options?.pingInterval ?? "5 seconds"
|
|
1250
1250
|
const timeoutMillis = Duration.toMillis(options?.pingTimeout ?? interval)
|
|
1251
1251
|
let lastSeen = clock.currentTimeMillisUnsafe()
|
|
1252
|
+
let awaitingResponse = false
|
|
1252
1253
|
const latch = Latch.makeUnsafe()
|
|
1253
1254
|
const onFrame = () => {
|
|
1254
1255
|
lastSeen = clock.currentTimeMillisUnsafe()
|
|
1256
|
+
awaitingResponse = false
|
|
1255
1257
|
}
|
|
1256
1258
|
const reset = () => {
|
|
1257
1259
|
onFrame()
|
|
1258
1260
|
latch.closeUnsafe()
|
|
1259
1261
|
}
|
|
1260
1262
|
yield* Effect.suspend((): Effect.Effect<void, E, R> => {
|
|
1261
|
-
|
|
1263
|
+
// A late tick must send a ping before it can declare the connection silent.
|
|
1264
|
+
// Keep the timeout measured from the last frame, including for custom timeouts.
|
|
1265
|
+
if (awaitingResponse && clock.currentTimeMillisUnsafe() - lastSeen > timeoutMillis) return latch.open
|
|
1266
|
+
awaitingResponse = true
|
|
1262
1267
|
return writePing
|
|
1263
1268
|
}).pipe(
|
|
1264
1269
|
Effect.delay(interval),
|
package/src/sql/SqlClient.ts
CHANGED
|
@@ -275,22 +275,22 @@ export const make = Effect.fnUntraced(function*(options: SqlClient.MakeOptions)
|
|
|
275
275
|
})
|
|
276
276
|
|
|
277
277
|
/**
|
|
278
|
-
* Builds the acquirers and failed-COMMIT cleanup for a SQLite client that
|
|
278
|
+
* Builds the acquirers, borrower and failed-COMMIT cleanup for a SQLite client that
|
|
279
279
|
* shares one connection through a semaphore.
|
|
280
280
|
*
|
|
281
281
|
* **Details**
|
|
282
282
|
*
|
|
283
283
|
* Both acquirers lease the connection into the current scope and hold the
|
|
284
|
-
* semaphore until that scope closes
|
|
285
|
-
*
|
|
286
|
-
* underneath
|
|
287
|
-
* have to run inside `Effect.scoped`.
|
|
284
|
+
* semaphore until that scope closes. The borrower holds the same semaphore
|
|
285
|
+
* until the statement finishes without creating a scope. Another fiber cannot
|
|
286
|
+
* begin a transaction underneath either. Effects that use the connection directly,
|
|
287
|
+
* such as an export, have to run inside `Effect.scoped`.
|
|
288
288
|
*
|
|
289
289
|
* SQLite can keep a transaction open after COMMIT fails, for example on a
|
|
290
290
|
* deferred foreign key violation. `onCommitFailure` rolls it back before the
|
|
291
291
|
* connection is reused. If that ROLLBACK fails, the connection is rejected, and
|
|
292
|
-
* each acquisition retries the ROLLBACK once while holding the semaphore
|
|
293
|
-
* it succeeds. The database is never reopened, and transactions started with a
|
|
292
|
+
* each acquisition or borrow retries the ROLLBACK once while holding the semaphore
|
|
293
|
+
* until it succeeds. The database is never reopened, and transactions started with a
|
|
294
294
|
* plain `BEGIN` are only touched after a failed cleanup.
|
|
295
295
|
*
|
|
296
296
|
* Pass `isTransaction` when the driver can report whether a transaction is
|
|
@@ -307,6 +307,7 @@ export const makeSqliteAcquirers = <C extends Connection.Connection>(options: {
|
|
|
307
307
|
readonly isTransaction?: ((conn: C) => boolean) | undefined
|
|
308
308
|
}): {
|
|
309
309
|
readonly acquirer: Effect.Effect<C, SqlError, Scope.Scope>
|
|
310
|
+
readonly borrower: Connection.Borrower
|
|
310
311
|
readonly transactionAcquirer: Effect.Effect<C, SqlError, Scope.Scope>
|
|
311
312
|
readonly onCommitFailure: (conn: Connection.Connection) => Effect.Effect<void, SqlError>
|
|
312
313
|
} => {
|
|
@@ -352,6 +353,7 @@ export const makeSqliteAcquirers = <C extends Connection.Connection>(options: {
|
|
|
352
353
|
|
|
353
354
|
return {
|
|
354
355
|
acquirer: lease,
|
|
356
|
+
borrower: (f) => semaphore.withPermit(Effect.flatMap(available, f)),
|
|
355
357
|
transactionAcquirer: lease,
|
|
356
358
|
onCommitFailure: (conn) => Effect.tapCause(rollback(conn as C), (cause) => Effect.sync(() => poison(cause)))
|
|
357
359
|
}
|
package/src/testing/TestClock.ts
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import * as Arr from "../Array.ts"
|
|
15
15
|
import * as Clock from "../Clock.ts"
|
|
16
|
+
import * as Context from "../Context.ts"
|
|
16
17
|
import * as Data from "../Data.ts"
|
|
17
18
|
import * as Duration from "../Duration.ts"
|
|
18
19
|
import * as Effect from "../Effect.ts"
|
|
19
20
|
import * as Fiber from "../Fiber.ts"
|
|
20
|
-
import { flow } from "../Function.ts"
|
|
21
21
|
import * as Latch from "../Latch.ts"
|
|
22
22
|
import * as Layer from "../Layer.ts"
|
|
23
|
-
import * as
|
|
23
|
+
import * as Scheduler from "../Scheduler.ts"
|
|
24
24
|
import * as Semaphore from "../Semaphore.ts"
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -40,6 +40,9 @@ import * as Semaphore from "../Semaphore.ts"
|
|
|
40
40
|
* the time is set to on or after the time they are scheduled to run. Fork the
|
|
41
41
|
* effect being tested, then adjust the clock time, and finally verify that the
|
|
42
42
|
* expected effects have been performed.
|
|
43
|
+
* The ordered execution of sleeps registered after multiple scheduler hops
|
|
44
|
+
* requires fibers running under {@link layer}; providing a clock from
|
|
45
|
+
* {@link make} by hand does not install the tracking scheduler.
|
|
43
46
|
*
|
|
44
47
|
* **Example** (Testing timeouts deterministically)
|
|
45
48
|
*
|
|
@@ -142,7 +145,8 @@ export declare namespace TestClock {
|
|
|
142
145
|
/**
|
|
143
146
|
* Options used when constructing a `TestClock`. `warningDelay` controls how
|
|
144
147
|
* long the live clock waits before logging a warning when a test uses time
|
|
145
|
-
* without advancing the test clock
|
|
148
|
+
* without advancing the test clock, or when a fiber woken by the test clock
|
|
149
|
+
* keeps running without suspending.
|
|
146
150
|
*
|
|
147
151
|
* **Example** (Configuring the warning delay)
|
|
148
152
|
*
|
|
@@ -170,7 +174,8 @@ export declare namespace TestClock {
|
|
|
170
174
|
export interface Options {
|
|
171
175
|
/**
|
|
172
176
|
* The amount of time to wait before displaying a warning message when a
|
|
173
|
-
* test is using time but is not advancing the `TestClock
|
|
177
|
+
* test is using time but is not advancing the `TestClock`, or when a fiber
|
|
178
|
+
* woken by `adjust` or `setTime` keeps running without suspending.
|
|
174
179
|
*/
|
|
175
180
|
readonly warningDelay?: Duration.Input
|
|
176
181
|
}
|
|
@@ -197,15 +202,30 @@ const warningMessage = "A test is using time, but is not advancing the test " +
|
|
|
197
202
|
"clock, which may result in the test hanging. Use TestClock.adjust to " +
|
|
198
203
|
"manually advance the time."
|
|
199
204
|
|
|
205
|
+
/**
|
|
206
|
+
* The warning message that will be displayed if a fiber woken by the
|
|
207
|
+
* `TestClock` does not suspend within the warning delay.
|
|
208
|
+
*/
|
|
209
|
+
const busyWarningMessage = "A fiber woken by the test clock is still running " +
|
|
210
|
+
"without suspending, so the test clock stopped waiting for it. Sleeps it " +
|
|
211
|
+
"starts later may be scheduled relative to a later time."
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The live clock of each `TestClock`, so a `TestClock` constructed while
|
|
215
|
+
* another one is the current clock uses the outer clock's live clock instead
|
|
216
|
+
* of the outer `TestClock`, which only advances when adjusted.
|
|
217
|
+
*/
|
|
218
|
+
const liveClocks = new WeakMap<Clock.Clock, Clock.Clock>()
|
|
219
|
+
|
|
220
|
+
interface WakeTracker {
|
|
221
|
+
pending: number
|
|
222
|
+
onIdle: (() => void) | undefined
|
|
223
|
+
}
|
|
224
|
+
|
|
200
225
|
const defaultOptions: Required<TestClock.Options> = {
|
|
201
226
|
warningDelay: "1 second"
|
|
202
227
|
}
|
|
203
228
|
|
|
204
|
-
const SleepOrder = Order.flip(Order.Struct({
|
|
205
|
-
timestamp: Order.Number,
|
|
206
|
-
sequence: Order.Number
|
|
207
|
-
}))
|
|
208
|
-
|
|
209
229
|
const nanosPerMilli = BigInt(1_000_000)
|
|
210
230
|
|
|
211
231
|
const millisToNanos = (millis: number): bigint => {
|
|
@@ -217,6 +237,14 @@ const millisToNanos = (millis: number): bigint => {
|
|
|
217
237
|
/**
|
|
218
238
|
* Creates a `TestClock` with optional configuration.
|
|
219
239
|
*
|
|
240
|
+
* **Gotchas**
|
|
241
|
+
*
|
|
242
|
+
* The guarantee that sleeps registered after multiple scheduler hops run in
|
|
243
|
+
* order applies only to fibers running under {@link layer}, which
|
|
244
|
+
* `@effect/vitest`'s `it.effect` uses. Providing a clock from `make` by hand
|
|
245
|
+
* waits only one scheduler turn after each woken sleep. Prefer `layer` when
|
|
246
|
+
* forked fibers sleep.
|
|
247
|
+
*
|
|
220
248
|
* **Example** (Creating a test clock)
|
|
221
249
|
*
|
|
222
250
|
* ```ts import.meta.vitest
|
|
@@ -245,18 +273,21 @@ const millisToNanos = (millis: number): bigint => {
|
|
|
245
273
|
* @category constructors
|
|
246
274
|
* @since 4.0.0
|
|
247
275
|
*/
|
|
248
|
-
export const make = Effect.
|
|
276
|
+
export const make = (options?: TestClock.Options) => Effect.map(makeWithScheduler(options), ([testClock]) => testClock)
|
|
277
|
+
|
|
278
|
+
const makeWithScheduler = Effect.fnUntraced(function*(
|
|
249
279
|
options?: TestClock.Options
|
|
250
280
|
) {
|
|
251
281
|
const config = { ...defaultOptions, ...options }
|
|
252
|
-
|
|
282
|
+
// Sorted by descending timestamp, so `pop` wakes the earliest sleep first
|
|
253
283
|
const sleeps: Array<{
|
|
254
|
-
readonly sequence: number
|
|
255
284
|
readonly timestamp: number
|
|
256
285
|
readonly latch: Latch.Latch
|
|
257
286
|
}> = []
|
|
258
|
-
const
|
|
287
|
+
const currentClock = yield* Clock.clockWith(Effect.succeed)
|
|
288
|
+
const liveClock = liveClocks.get(currentClock) ?? currentClock
|
|
259
289
|
const warningSemaphore = yield* Semaphore.make(1)
|
|
290
|
+
const parentScheduler = yield* Scheduler.Scheduler
|
|
260
291
|
|
|
261
292
|
let currentTimestamp: number = new Date(0).getTime()
|
|
262
293
|
let currentWallNanos = BigInt(0)
|
|
@@ -332,17 +363,97 @@ export const make = Effect.fnUntraced(function*(
|
|
|
332
363
|
const millis = Duration.toMillis(duration)
|
|
333
364
|
const end = currentTimestamp + millis
|
|
334
365
|
if (end <= currentTimestamp) return
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
366
|
+
yield* Effect.acquireUseRelease(
|
|
367
|
+
Effect.sync(() => {
|
|
368
|
+
const entry = { timestamp: end, latch: Latch.makeUnsafe() }
|
|
369
|
+
// Insert before entries with an equal timestamp, so they wake in
|
|
370
|
+
// registration order
|
|
371
|
+
let low = 0
|
|
372
|
+
let high = sleeps.length
|
|
373
|
+
while (low < high) {
|
|
374
|
+
const mid = (low + high) >>> 1
|
|
375
|
+
if (sleeps[mid].timestamp > end) low = mid + 1
|
|
376
|
+
else high = mid
|
|
377
|
+
}
|
|
378
|
+
sleeps.splice(low, 0, entry)
|
|
379
|
+
return entry
|
|
380
|
+
}),
|
|
381
|
+
(entry) => Effect.andThen(warningStart, entry.latch.await),
|
|
382
|
+
(entry) =>
|
|
383
|
+
Effect.sync(() => {
|
|
384
|
+
// The entry is already gone if `run` popped it
|
|
385
|
+
const index = sleeps.indexOf(entry)
|
|
386
|
+
if (index !== -1) sleeps.splice(index, 1)
|
|
387
|
+
})
|
|
388
|
+
)
|
|
344
389
|
})
|
|
345
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Tasks scheduled while waking a sleeper, and tasks scheduled by those tasks,
|
|
393
|
+
* are counted by that wake's tracker so `run` can wait for the woken fiber,
|
|
394
|
+
* and any fibers it resumes or forks, to suspend before checking the next
|
|
395
|
+
* sleep.
|
|
396
|
+
*/
|
|
397
|
+
let currentTracker: WakeTracker | undefined = undefined
|
|
398
|
+
|
|
399
|
+
function runTracked(tracker: WakeTracker, f: () => void): void {
|
|
400
|
+
const previous = currentTracker
|
|
401
|
+
currentTracker = tracker
|
|
402
|
+
try {
|
|
403
|
+
f()
|
|
404
|
+
} finally {
|
|
405
|
+
currentTracker = previous
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const scheduler: Scheduler.Scheduler = {
|
|
410
|
+
executionMode: parentScheduler.executionMode,
|
|
411
|
+
shouldYield: (fiber) => parentScheduler.shouldYield(fiber),
|
|
412
|
+
makeDispatcher() {
|
|
413
|
+
const dispatcher = parentScheduler.makeDispatcher()
|
|
414
|
+
return {
|
|
415
|
+
scheduleTask(task, priority) {
|
|
416
|
+
const tracker = currentTracker
|
|
417
|
+
if (tracker === undefined) {
|
|
418
|
+
return dispatcher.scheduleTask(task, priority)
|
|
419
|
+
}
|
|
420
|
+
tracker.pending++
|
|
421
|
+
dispatcher.scheduleTask(() => {
|
|
422
|
+
try {
|
|
423
|
+
runTracked(tracker, task)
|
|
424
|
+
} finally {
|
|
425
|
+
if (--tracker.pending === 0) tracker.onIdle?.()
|
|
426
|
+
}
|
|
427
|
+
}, priority)
|
|
428
|
+
},
|
|
429
|
+
flush() {
|
|
430
|
+
dispatcher.flush()
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const wake = (latch: Latch.Latch) =>
|
|
437
|
+
Effect.suspend(() => {
|
|
438
|
+
const tracker: WakeTracker = { pending: 0, onIdle: undefined }
|
|
439
|
+
runTracked(tracker, () => latch.openUnsafe())
|
|
440
|
+
if (tracker.pending === 0) return Effect.yieldNow
|
|
441
|
+
return Effect.callback<void>((resume) => {
|
|
442
|
+
if (tracker.pending === 0) return resume(Effect.void)
|
|
443
|
+
tracker.onIdle = () => resume(Effect.void)
|
|
444
|
+
return Effect.sync(() => {
|
|
445
|
+
tracker.onIdle = undefined
|
|
446
|
+
})
|
|
447
|
+
}).pipe(
|
|
448
|
+
Effect.timeoutOrElse({
|
|
449
|
+
duration: config.warningDelay,
|
|
450
|
+
orElse: () => Effect.logWarning(busyWarningMessage)
|
|
451
|
+
}),
|
|
452
|
+
withLive,
|
|
453
|
+
Effect.andThen(Effect.yieldNow)
|
|
454
|
+
)
|
|
455
|
+
})
|
|
456
|
+
|
|
346
457
|
const runSemaphore = yield* Semaphore.make(1)
|
|
347
458
|
const run = Effect.fnUntraced(function*(
|
|
348
459
|
step: (currentTimestamp: number) => number,
|
|
@@ -366,8 +477,7 @@ export const make = Effect.fnUntraced(function*(
|
|
|
366
477
|
if (Arr.lastNonEmpty(sleeps).timestamp > endTimestamp) break
|
|
367
478
|
const entry = sleeps.pop()!
|
|
368
479
|
advanceTo(entry.timestamp)
|
|
369
|
-
entry.latch
|
|
370
|
-
yield* Effect.yieldNow
|
|
480
|
+
yield* wake(entry.latch)
|
|
371
481
|
}
|
|
372
482
|
advanceTo(endTimestamp)
|
|
373
483
|
if (adjustmentNanos !== undefined && Number.isFinite(endTimestamp)) {
|
|
@@ -391,7 +501,7 @@ export const make = Effect.fnUntraced(function*(
|
|
|
391
501
|
|
|
392
502
|
yield* Effect.addFinalizer(() => warningDone)
|
|
393
503
|
|
|
394
|
-
|
|
504
|
+
const testClock = {
|
|
395
505
|
currentTimeMillisUnsafe,
|
|
396
506
|
currentTimeNanosUnsafe,
|
|
397
507
|
monotonicTimeNanosUnsafe,
|
|
@@ -403,6 +513,8 @@ export const make = Effect.fnUntraced(function*(
|
|
|
403
513
|
sleep,
|
|
404
514
|
withLive
|
|
405
515
|
}
|
|
516
|
+
liveClocks.set(testClock, liveClock)
|
|
517
|
+
return [testClock, scheduler] as const
|
|
406
518
|
})
|
|
407
519
|
|
|
408
520
|
/**
|
|
@@ -438,10 +550,13 @@ export const make = Effect.fnUntraced(function*(
|
|
|
438
550
|
* @category layers
|
|
439
551
|
* @since 4.0.0
|
|
440
552
|
*/
|
|
441
|
-
export const layer
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
)
|
|
553
|
+
export const layer = (options?: TestClock.Options): Layer.Layer<TestClock> =>
|
|
554
|
+
Layer.effectContext(
|
|
555
|
+
Effect.map(makeWithScheduler(options), ([testClock, scheduler]) =>
|
|
556
|
+
Context.make(Clock.Clock, testClock).pipe(
|
|
557
|
+
Context.add(Scheduler.Scheduler, scheduler)
|
|
558
|
+
))
|
|
559
|
+
) as any
|
|
445
560
|
|
|
446
561
|
/**
|
|
447
562
|
* Retrieves the `TestClock` service for this test and uses it to run the
|
package/src/workflow/Activity.ts
CHANGED
|
@@ -347,6 +347,7 @@ const makeExecute = Effect.fnUntraced(function*<
|
|
|
347
347
|
(_) => _._tag === "Suspended"
|
|
348
348
|
)
|
|
349
349
|
if (result._tag === "Suspended") {
|
|
350
|
+
if (result.failed) instance.failed = true
|
|
350
351
|
return yield* Workflow.suspend(instance)
|
|
351
352
|
}
|
|
352
353
|
return yield* result.exit
|
package/src/workflow/Workflow.ts
CHANGED
|
@@ -78,11 +78,26 @@ export interface Workflow<
|
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Execute the workflow with the given payload.
|
|
81
|
+
*
|
|
82
|
+
* **Details**
|
|
83
|
+
*
|
|
84
|
+
* `discard: true` returns the execution ID without waiting for the result.
|
|
85
|
+
* The child remains linked to its parent for completion wakes and interruption.
|
|
86
|
+
*
|
|
87
|
+
* With `discard: true, detached: true`, the child neither wakes its parent
|
|
88
|
+
* nor gets interrupted with it. The cluster engine retains the parent for
|
|
89
|
+
* observability.
|
|
90
|
+
*
|
|
91
|
+
* **Gotchas**
|
|
92
|
+
*
|
|
93
|
+
* Do not await a detached execution later. Executing the same payload joins
|
|
94
|
+
* it, but its completion will not wake the awaiting workflow.
|
|
81
95
|
*/
|
|
82
96
|
readonly execute: <const Discard extends boolean = false>(
|
|
83
97
|
payload: Payload["~type.make.in"],
|
|
84
98
|
options?: {
|
|
85
99
|
readonly discard?: Discard
|
|
100
|
+
readonly detached?: [Discard] extends [true] ? boolean | undefined : undefined
|
|
86
101
|
}
|
|
87
102
|
) => Effect.Effect<
|
|
88
103
|
Discard extends true ? string : Success["Type"],
|
|
@@ -248,7 +263,7 @@ export interface AnyWithProps extends Any {
|
|
|
248
263
|
readonly errorSchema: Schema.Top
|
|
249
264
|
readonly execute: (
|
|
250
265
|
payload: any,
|
|
251
|
-
options?: { readonly discard?: boolean }
|
|
266
|
+
options?: { readonly discard?: boolean; readonly detached?: boolean | undefined }
|
|
252
267
|
) => Effect.Effect<any, any, any>
|
|
253
268
|
readonly resume: (
|
|
254
269
|
executionId: string
|
|
@@ -352,7 +367,7 @@ const Proto = {
|
|
|
352
367
|
execute<const Discard extends boolean = false>(
|
|
353
368
|
this: AnyWithProps,
|
|
354
369
|
fields: any,
|
|
355
|
-
opts?: { readonly discard?: Discard } | undefined
|
|
370
|
+
opts?: { readonly discard?: Discard; readonly detached?: boolean | undefined } | undefined
|
|
356
371
|
) {
|
|
357
372
|
return Effect.suspend(() => {
|
|
358
373
|
const payload = this.payloadSchema.make(fields)
|
|
@@ -366,6 +381,7 @@ const Proto = {
|
|
|
366
381
|
executionId,
|
|
367
382
|
payload,
|
|
368
383
|
discard: opts?.discard,
|
|
384
|
+
detached: opts?.detached,
|
|
369
385
|
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
370
386
|
})
|
|
371
387
|
))
|
|
@@ -617,6 +633,11 @@ export class Complete<A, E> extends Data.TaggedClass("Complete")<{
|
|
|
617
633
|
* Represents a suspended workflow execution, optionally carrying the cause that
|
|
618
634
|
* triggered suspension.
|
|
619
635
|
*
|
|
636
|
+
* **Details**
|
|
637
|
+
*
|
|
638
|
+
* `failed` marks this execution's own `SuspendOnFailure` and requires explicit
|
|
639
|
+
* `resume` or `interrupt`. Inherited child failures do not set it.
|
|
640
|
+
*
|
|
620
641
|
* @stability unstable
|
|
621
642
|
* @category schemas
|
|
622
643
|
* @since 4.0.0
|
|
@@ -625,7 +646,8 @@ export class Suspended extends Schema.Class<Suspended>(
|
|
|
625
646
|
"effect/workflow/Workflow/Suspended"
|
|
626
647
|
)({
|
|
627
648
|
_tag: Schema.tag("Suspended"),
|
|
628
|
-
cause: Schema.optional(Schema.Cause(Schema.Never, Schema.Defect()))
|
|
649
|
+
cause: Schema.optional(Schema.Cause(Schema.Never, Schema.Defect())),
|
|
650
|
+
failed: Schema.optional(Schema.Boolean)
|
|
629
651
|
}) {
|
|
630
652
|
/**
|
|
631
653
|
* Marks this value as a workflow result for runtime guards.
|
|
@@ -697,11 +719,13 @@ export const intoResult = <A, E, R>(
|
|
|
697
719
|
Effect.interruptible,
|
|
698
720
|
suspendOnFailure
|
|
699
721
|
? Effect.catchCause((cause) => {
|
|
700
|
-
if (instance.abandoned) {
|
|
722
|
+
if (instance.abandoned || instance.interrupted) {
|
|
701
723
|
return Effect.failCause(cause)
|
|
702
724
|
}
|
|
703
725
|
instance.suspended = true
|
|
726
|
+
// Ordinary suspension is a self-interrupt and also reaches here.
|
|
704
727
|
if (!Cause.hasInterruptsOnly(cause)) {
|
|
728
|
+
instance.failed = true
|
|
705
729
|
instance.cause = Cause.die(Cause.squash(cause))
|
|
706
730
|
}
|
|
707
731
|
return Effect.interrupt
|
|
@@ -720,7 +744,9 @@ export const intoResult = <A, E, R>(
|
|
|
720
744
|
const abandoned = instance.abandoned && !instance.interrupted && hasInterruptsOnly
|
|
721
745
|
instance.abandoned = abandoned
|
|
722
746
|
if (instance.suspended && hasInterruptsOnly && !abandoned) {
|
|
723
|
-
return Effect.succeed(
|
|
747
|
+
return Effect.succeed(
|
|
748
|
+
new Suspended(instance.failed ? { cause: instance.cause, failed: true } : { cause: instance.cause })
|
|
749
|
+
)
|
|
724
750
|
}
|
|
725
751
|
if (!instance.interrupted && hasInterruptsOnly) {
|
|
726
752
|
// External interrupts exit without a result. When the cluster has
|