effect 4.0.0-beta.40 → 4.0.0-beta.42
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/dist/BigDecimal.d.ts +36 -0
- package/dist/BigDecimal.d.ts.map +1 -1
- package/dist/BigDecimal.js +52 -0
- package/dist/BigDecimal.js.map +1 -1
- package/dist/Effect.d.ts +20 -63
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +24 -65
- package/dist/Effect.js.map +1 -1
- package/dist/Layer.js +1 -1
- package/dist/Layer.js.map +1 -1
- package/dist/ManagedRuntime.d.ts.map +1 -1
- package/dist/ManagedRuntime.js +19 -7
- package/dist/ManagedRuntime.js.map +1 -1
- package/dist/MutableList.d.ts.map +1 -1
- package/dist/MutableList.js +3 -0
- package/dist/MutableList.js.map +1 -1
- package/dist/Number.d.ts.map +1 -1
- package/dist/Number.js +12 -3
- package/dist/Number.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +16 -14
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/ServiceMap.d.ts +14 -26
- package/dist/ServiceMap.d.ts.map +1 -1
- package/dist/ServiceMap.js +6 -5
- package/dist/ServiceMap.js.map +1 -1
- package/dist/TxChunk.d.ts +39 -39
- package/dist/TxChunk.d.ts.map +1 -1
- package/dist/TxChunk.js +3 -3
- package/dist/TxChunk.js.map +1 -1
- package/dist/TxDeferred.d.ts +9 -9
- package/dist/TxDeferred.d.ts.map +1 -1
- package/dist/TxDeferred.js +2 -2
- package/dist/TxDeferred.js.map +1 -1
- package/dist/TxHashMap.d.ts +59 -59
- package/dist/TxHashMap.d.ts.map +1 -1
- package/dist/TxHashMap.js +8 -8
- package/dist/TxHashMap.js.map +1 -1
- package/dist/TxHashSet.d.ts +35 -35
- package/dist/TxHashSet.d.ts.map +1 -1
- package/dist/TxHashSet.js +7 -7
- package/dist/TxHashSet.js.map +1 -1
- package/dist/TxPriorityQueue.d.ts +23 -23
- package/dist/TxPriorityQueue.d.ts.map +1 -1
- package/dist/TxPriorityQueue.js +4 -4
- package/dist/TxPriorityQueue.js.map +1 -1
- package/dist/TxPubSub.d.ts +14 -14
- package/dist/TxPubSub.d.ts.map +1 -1
- package/dist/TxPubSub.js +12 -12
- package/dist/TxPubSub.js.map +1 -1
- package/dist/TxQueue.d.ts +33 -33
- package/dist/TxQueue.d.ts.map +1 -1
- package/dist/TxQueue.js +29 -44
- package/dist/TxQueue.js.map +1 -1
- package/dist/TxReentrantLock.d.ts +10 -33
- package/dist/TxReentrantLock.d.ts.map +1 -1
- package/dist/TxReentrantLock.js +14 -37
- package/dist/TxReentrantLock.js.map +1 -1
- package/dist/TxRef.d.ts +36 -42
- package/dist/TxRef.d.ts.map +1 -1
- package/dist/TxRef.js +16 -25
- package/dist/TxRef.js.map +1 -1
- package/dist/TxSemaphore.d.ts +8 -8
- package/dist/TxSemaphore.d.ts.map +1 -1
- package/dist/TxSemaphore.js +10 -10
- package/dist/TxSemaphore.js.map +1 -1
- package/dist/TxSubscriptionRef.d.ts +14 -14
- package/dist/TxSubscriptionRef.d.ts.map +1 -1
- package/dist/TxSubscriptionRef.js +5 -5
- package/dist/TxSubscriptionRef.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/internal/effect.js +3 -0
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/schema/representation.js +28 -0
- package/dist/internal/schema/representation.js.map +1 -1
- package/dist/unstable/ai/Chat.d.ts +31 -2
- package/dist/unstable/ai/Chat.d.ts.map +1 -1
- package/dist/unstable/ai/Chat.js.map +1 -1
- package/dist/unstable/ai/LanguageModel.d.ts +68 -6
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +88 -11
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/ai/OpenAiStructuredOutput.js +3 -0
- package/dist/unstable/ai/OpenAiStructuredOutput.js.map +1 -1
- package/dist/unstable/cli/Prompt.js +1 -1
- package/dist/unstable/cli/Prompt.js.map +1 -1
- package/dist/unstable/cli/internal/command.d.ts.map +1 -1
- package/dist/unstable/cli/internal/command.js +12 -1
- package/dist/unstable/cli/internal/command.js.map +1 -1
- package/dist/unstable/cluster/ClusterSchema.d.ts +18 -0
- package/dist/unstable/cluster/ClusterSchema.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterSchema.js +21 -1
- package/dist/unstable/cluster/ClusterSchema.js.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.js +6 -3
- package/dist/unstable/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/unstable/cluster/Entity.d.ts.map +1 -1
- package/dist/unstable/cluster/Entity.js +1 -0
- package/dist/unstable/cluster/Entity.js.map +1 -1
- package/dist/unstable/cluster/Message.d.ts +4 -2
- package/dist/unstable/cluster/Message.d.ts.map +1 -1
- package/dist/unstable/cluster/Message.js +13 -6
- package/dist/unstable/cluster/Message.js.map +1 -1
- package/dist/unstable/cluster/MessageStorage.d.ts +23 -0
- package/dist/unstable/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/unstable/cluster/MessageStorage.js +22 -7
- package/dist/unstable/cluster/MessageStorage.js.map +1 -1
- package/dist/unstable/cluster/Sharding.d.ts.map +1 -1
- package/dist/unstable/cluster/Sharding.js +24 -20
- package/dist/unstable/cluster/Sharding.js.map +1 -1
- package/dist/unstable/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/unstable/cluster/SqlMessageStorage.js +3 -1
- package/dist/unstable/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/unstable/cluster/internal/entityManager.js +10 -4
- package/dist/unstable/cluster/internal/entityManager.js.map +1 -1
- package/dist/unstable/http/index.d.ts +2 -2
- package/dist/unstable/http/index.d.ts.map +1 -1
- package/dist/unstable/http/index.js +2 -2
- package/dist/unstable/http/index.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiSchema.d.ts +1 -3
- package/dist/unstable/httpapi/HttpApiSchema.d.ts.map +1 -1
- package/dist/unstable/httpapi/OpenApi.d.ts +1 -0
- package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
- package/dist/unstable/rpc/Rpc.d.ts +1 -0
- package/dist/unstable/rpc/Rpc.d.ts.map +1 -1
- package/dist/unstable/rpc/Rpc.js.map +1 -1
- package/dist/unstable/rpc/RpcClient.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcClient.js +43 -26
- package/dist/unstable/rpc/RpcClient.js.map +1 -1
- package/dist/unstable/socket/Socket.d.ts +1 -1
- package/dist/unstable/socket/Socket.d.ts.map +1 -1
- package/dist/unstable/socket/Socket.js +1 -1
- package/dist/unstable/socket/Socket.js.map +1 -1
- package/dist/unstable/workflow/Activity.d.ts +5 -0
- package/dist/unstable/workflow/Activity.d.ts.map +1 -1
- package/dist/unstable/workflow/Activity.js +13 -0
- package/dist/unstable/workflow/Activity.js.map +1 -1
- package/package.json +1 -1
- package/src/BigDecimal.ts +54 -0
- package/src/Effect.ts +25 -75
- package/src/Layer.ts +1 -1
- package/src/ManagedRuntime.ts +33 -20
- package/src/MutableList.ts +3 -0
- package/src/Number.ts +13 -3
- package/src/SchemaRepresentation.ts +8 -6
- package/src/ServiceMap.ts +16 -31
- package/src/TxChunk.ts +53 -62
- package/src/TxDeferred.ts +14 -17
- package/src/TxHashMap.ts +91 -101
- package/src/TxHashSet.ts +68 -70
- package/src/TxPriorityQueue.ts +34 -38
- package/src/TxPubSub.ts +30 -32
- package/src/TxQueue.ts +70 -84
- package/src/TxReentrantLock.ts +30 -54
- package/src/TxRef.ts +53 -65
- package/src/TxSemaphore.ts +23 -24
- package/src/TxSubscriptionRef.ts +25 -27
- package/src/index.ts +6 -6
- package/src/internal/effect.ts +3 -0
- package/src/internal/schema/representation.ts +28 -0
- package/src/unstable/ai/Chat.ts +79 -18
- package/src/unstable/ai/LanguageModel.ts +182 -66
- package/src/unstable/ai/OpenAiStructuredOutput.ts +3 -0
- package/src/unstable/cli/Prompt.ts +3 -1
- package/src/unstable/cli/internal/command.ts +16 -1
- package/src/unstable/cluster/ClusterSchema.ts +29 -1
- package/src/unstable/cluster/ClusterWorkflowEngine.ts +22 -3
- package/src/unstable/cluster/Entity.ts +1 -0
- package/src/unstable/cluster/Message.ts +22 -10
- package/src/unstable/cluster/MessageStorage.ts +37 -6
- package/src/unstable/cluster/Sharding.ts +31 -23
- package/src/unstable/cluster/SqlMessageStorage.ts +6 -1
- package/src/unstable/cluster/internal/entityManager.ts +14 -5
- package/src/unstable/http/index.ts +2 -2
- package/src/unstable/httpapi/HttpApiSchema.ts +1 -1
- package/src/unstable/httpapi/OpenApi.ts +1 -0
- package/src/unstable/rpc/Rpc.ts +1 -0
- package/src/unstable/rpc/RpcClient.ts +45 -33
- package/src/unstable/socket/Socket.ts +1 -1
- package/src/unstable/workflow/Activity.ts +23 -0
|
@@ -6,6 +6,7 @@ import { Clock } from "../../Clock.ts"
|
|
|
6
6
|
import * as Data from "../../Data.ts"
|
|
7
7
|
import * as Effect from "../../Effect.ts"
|
|
8
8
|
import * as Exit from "../../Exit.ts"
|
|
9
|
+
import { constFalse, identity } from "../../Function.ts"
|
|
9
10
|
import * as Latch from "../../Latch.ts"
|
|
10
11
|
import * as Layer from "../../Layer.ts"
|
|
11
12
|
import * as Option from "../../Option.ts"
|
|
@@ -140,6 +141,13 @@ export class MessageStorage extends ServiceMap.Service<MessageStorage, {
|
|
|
140
141
|
readonly clearAddress: (
|
|
141
142
|
address: EntityAddress
|
|
142
143
|
) => Effect.Effect<void, PersistenceError>
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Used to wrap requests with transactions.
|
|
147
|
+
*/
|
|
148
|
+
readonly withTransaction: <A, E, R>(
|
|
149
|
+
effect: Effect.Effect<A, E, R>
|
|
150
|
+
) => Effect.Effect<A, E, R>
|
|
143
151
|
}>()("effect/cluster/MessageStorage") {}
|
|
144
152
|
|
|
145
153
|
/**
|
|
@@ -315,6 +323,13 @@ export type Encoded = {
|
|
|
315
323
|
readonly resetShards: (
|
|
316
324
|
shardIds: Arr.NonEmptyArray<string>
|
|
317
325
|
) => Effect.Effect<void, PersistenceError>
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Used to wrap requests with transactions.
|
|
329
|
+
*/
|
|
330
|
+
readonly withTransaction: <A, E, R>(
|
|
331
|
+
effect: Effect.Effect<A, E, R>
|
|
332
|
+
) => Effect.Effect<A, E, R>
|
|
318
333
|
}
|
|
319
334
|
|
|
320
335
|
/**
|
|
@@ -517,20 +532,22 @@ export const makeEncoded: (encoded: Encoded) => Effect.Effect<
|
|
|
517
532
|
const primaryKey = Envelope.primaryKeyByAddress(options)
|
|
518
533
|
return encoded.requestIdForPrimaryKey(primaryKey)
|
|
519
534
|
},
|
|
520
|
-
unprocessedMessages
|
|
535
|
+
unprocessedMessages(shardIds) {
|
|
536
|
+
const storage = this as MessageStorage["Service"]
|
|
521
537
|
const shards = Array.from(shardIds, (id) => id.toString())
|
|
522
538
|
if (!Arr.isArrayNonEmpty(shards)) return Effect.succeed([])
|
|
523
539
|
return Effect.flatMap(
|
|
524
540
|
Effect.suspend(() => encoded.unprocessedMessages(shards, clock.currentTimeMillisUnsafe())),
|
|
525
|
-
decodeMessages
|
|
541
|
+
(messages) => decodeMessages(storage, messages)
|
|
526
542
|
)
|
|
527
543
|
},
|
|
528
544
|
unprocessedMessagesById(messageIds) {
|
|
545
|
+
const storage = this as MessageStorage["Service"]
|
|
529
546
|
const ids = Array.from(messageIds)
|
|
530
547
|
if (!Arr.isArrayNonEmpty(ids)) return Effect.succeed([])
|
|
531
548
|
return Effect.flatMap(
|
|
532
549
|
Effect.suspend(() => encoded.unprocessedMessagesById(ids, clock.currentTimeMillisUnsafe())),
|
|
533
|
-
decodeMessages
|
|
550
|
+
(messages) => decodeMessages(storage, messages)
|
|
534
551
|
)
|
|
535
552
|
},
|
|
536
553
|
resetAddress: encoded.resetAddress,
|
|
@@ -539,10 +556,12 @@ export const makeEncoded: (encoded: Encoded) => Effect.Effect<
|
|
|
539
556
|
const shards = Array.from(shardIds, (id) => id.toString())
|
|
540
557
|
if (!Arr.isArrayNonEmpty(shards)) return Effect.void
|
|
541
558
|
return encoded.resetShards(shards)
|
|
542
|
-
}
|
|
559
|
+
},
|
|
560
|
+
withTransaction: encoded.withTransaction
|
|
543
561
|
})
|
|
544
562
|
|
|
545
563
|
const decodeMessages = (
|
|
564
|
+
storage: MessageStorage["Service"],
|
|
546
565
|
envelopes: Array<{
|
|
547
566
|
readonly envelope: Envelope.Encoded
|
|
548
567
|
readonly lastSentReply: Option.Option<Reply.Encoded>
|
|
@@ -659,7 +678,8 @@ export const noop: MessageStorage["Service"] = Effect.runSync(make({
|
|
|
659
678
|
unprocessedMessagesById: () => Effect.succeed([]),
|
|
660
679
|
resetAddress: () => Effect.void,
|
|
661
680
|
clearAddress: () => Effect.void,
|
|
662
|
-
resetShards: () => Effect.void
|
|
681
|
+
resetShards: () => Effect.void,
|
|
682
|
+
withTransaction: identity
|
|
663
683
|
}))
|
|
664
684
|
|
|
665
685
|
/**
|
|
@@ -673,6 +693,16 @@ export type MemoryEntry = {
|
|
|
673
693
|
deliverAt: number | null
|
|
674
694
|
}
|
|
675
695
|
|
|
696
|
+
/**
|
|
697
|
+
* Can be used in tests to simulate a transaction.
|
|
698
|
+
*
|
|
699
|
+
* @since 4.0.0
|
|
700
|
+
* @category Memory
|
|
701
|
+
*/
|
|
702
|
+
export const MemoryTransaction = ServiceMap.Reference<boolean>("effect/cluster/MessageStorage/MemoryTransaction", {
|
|
703
|
+
defaultValue: constFalse
|
|
704
|
+
})
|
|
705
|
+
|
|
676
706
|
/**
|
|
677
707
|
* @since 4.0.0
|
|
678
708
|
* @category Memory
|
|
@@ -859,7 +889,8 @@ export class MemoryDriver extends ServiceMap.Service<MemoryDriver>()("effect/clu
|
|
|
859
889
|
journal.splice(i, 1)
|
|
860
890
|
}
|
|
861
891
|
}),
|
|
862
|
-
resetShards: () => Effect.void
|
|
892
|
+
resetShards: () => Effect.void,
|
|
893
|
+
withTransaction: Effect.provideService(MemoryTransaction, true)
|
|
863
894
|
}
|
|
864
895
|
|
|
865
896
|
const storage = yield* makeEncoded(encoded)
|
|
@@ -820,7 +820,10 @@ const make = Effect.gen(function*() {
|
|
|
820
820
|
return Effect.catchFilter(
|
|
821
821
|
Effect.suspend(() => {
|
|
822
822
|
const address = message.envelope.address
|
|
823
|
-
const isPersisted = ServiceMap.get(
|
|
823
|
+
const isPersisted = ServiceMap.get(
|
|
824
|
+
message._tag === "OutgoingRequest" ? message.annotations : message.rpc.annotations,
|
|
825
|
+
Persisted
|
|
826
|
+
)
|
|
824
827
|
if (isPersisted && !storageEnabled) {
|
|
825
828
|
return Effect.die("Sharding.sendOutgoing: Persisted messages require MessageStorage")
|
|
826
829
|
}
|
|
@@ -1000,6 +1003,7 @@ const make = Effect.gen(function*() {
|
|
|
1000
1003
|
type ClientRequestEntry = {
|
|
1001
1004
|
readonly rpc: Rpc.AnyWithProps
|
|
1002
1005
|
readonly services: ServiceMap.ServiceMap<never>
|
|
1006
|
+
readonly message: Message.OutgoingRequest<any>
|
|
1003
1007
|
lastChunkId?: Snowflake.Snowflake
|
|
1004
1008
|
}
|
|
1005
1009
|
const clientRequests = new Map<Snowflake.Snowflake, ClientRequestEntry>()
|
|
@@ -1029,35 +1033,39 @@ const make = Effect.gen(function*() {
|
|
|
1029
1033
|
const id = Snowflake.Snowflake(options.message.id)
|
|
1030
1034
|
const rpc = entity.protocol.requests.get(options.message.tag)!
|
|
1031
1035
|
let respond: (reply: Reply.Reply<any>) => Effect.Effect<void>
|
|
1036
|
+
const envelope = Envelope.makeRequest<any>({
|
|
1037
|
+
requestId: id,
|
|
1038
|
+
address,
|
|
1039
|
+
tag: options.message.tag,
|
|
1040
|
+
payload: options.message.payload,
|
|
1041
|
+
headers: options.message.headers,
|
|
1042
|
+
traceId: options.message.traceId,
|
|
1043
|
+
spanId: options.message.spanId,
|
|
1044
|
+
sampled: options.message.sampled
|
|
1045
|
+
})
|
|
1046
|
+
const message = new Message.OutgoingRequest({
|
|
1047
|
+
envelope,
|
|
1048
|
+
lastReceivedReply: Option.none(),
|
|
1049
|
+
rpc,
|
|
1050
|
+
services: fiber.services as ServiceMap.ServiceMap<any>,
|
|
1051
|
+
respond: (reply) => respond(reply),
|
|
1052
|
+
annotations: ServiceMap.get(rpc.annotations, ClusterSchema.Dynamic)(
|
|
1053
|
+
rpc.annotations,
|
|
1054
|
+
envelope as any
|
|
1055
|
+
)
|
|
1056
|
+
})
|
|
1032
1057
|
if (!options.discard) {
|
|
1033
1058
|
const entry: ClientRequestEntry = {
|
|
1034
1059
|
rpc: rpc as any,
|
|
1035
|
-
services: fiber.currentContext
|
|
1060
|
+
services: fiber.currentContext,
|
|
1061
|
+
message
|
|
1036
1062
|
}
|
|
1037
1063
|
clientRequests.set(id, entry)
|
|
1038
1064
|
respond = makeClientRespond(entry, client.write)
|
|
1039
1065
|
} else {
|
|
1040
1066
|
respond = clientRespondDiscard
|
|
1041
1067
|
}
|
|
1042
|
-
return sendOutgoing(
|
|
1043
|
-
new Message.OutgoingRequest({
|
|
1044
|
-
envelope: Envelope.makeRequest({
|
|
1045
|
-
requestId: id,
|
|
1046
|
-
address,
|
|
1047
|
-
tag: options.message.tag,
|
|
1048
|
-
payload: options.message.payload,
|
|
1049
|
-
headers: options.message.headers,
|
|
1050
|
-
traceId: options.message.traceId,
|
|
1051
|
-
spanId: options.message.spanId,
|
|
1052
|
-
sampled: options.message.sampled
|
|
1053
|
-
}),
|
|
1054
|
-
lastReceivedReply: Option.none(),
|
|
1055
|
-
rpc,
|
|
1056
|
-
services: fiber.services as ServiceMap.ServiceMap<any>,
|
|
1057
|
-
respond
|
|
1058
|
-
}),
|
|
1059
|
-
options.discard
|
|
1060
|
-
)
|
|
1068
|
+
return sendOutgoing(message, options.discard)
|
|
1061
1069
|
}
|
|
1062
1070
|
case "Ack": {
|
|
1063
1071
|
const requestId = Snowflake.Snowflake(options.message.requestId)
|
|
@@ -1081,14 +1089,14 @@ const make = Effect.gen(function*() {
|
|
|
1081
1089
|
const entry = clientRequests.get(requestId)!
|
|
1082
1090
|
if (!entry) return Effect.void
|
|
1083
1091
|
clientRequests.delete(requestId)
|
|
1084
|
-
if (ClusterSchema.isUninterruptibleForClient(entry.
|
|
1092
|
+
if (ClusterSchema.isUninterruptibleForClient(entry.message.annotations)) {
|
|
1085
1093
|
return Effect.void
|
|
1086
1094
|
}
|
|
1087
1095
|
// for durable messages, we ignore interrupts on shutdown or as a
|
|
1088
1096
|
// result of a shard being resassigned
|
|
1089
1097
|
const isTransientInterrupt = MutableRef.get(isShutdown) ||
|
|
1090
1098
|
options.message.interruptors.some((id) => internalInterruptors.has(id))
|
|
1091
|
-
if (isTransientInterrupt && ServiceMap.get(entry.
|
|
1099
|
+
if (isTransientInterrupt && ServiceMap.get(entry.message.annotations, Persisted)) {
|
|
1092
1100
|
return Effect.void
|
|
1093
1101
|
}
|
|
1094
1102
|
return Effect.ignore(sendOutgoing(
|
|
@@ -9,7 +9,7 @@ import * as Schedule from "../../Schedule.ts"
|
|
|
9
9
|
import * as Migrator from "../sql/Migrator.ts"
|
|
10
10
|
import * as SqlClient from "../sql/SqlClient.ts"
|
|
11
11
|
import type { Row } from "../sql/SqlConnection.ts"
|
|
12
|
-
import type
|
|
12
|
+
import { isSqlError, type SqlError } from "../sql/SqlError.ts"
|
|
13
13
|
import { PersistenceError } from "./ClusterError.ts"
|
|
14
14
|
import type * as Envelope from "./Envelope.ts"
|
|
15
15
|
import * as MessageStorage from "./MessageStorage.ts"
|
|
@@ -592,6 +592,11 @@ export const make: (options?: {
|
|
|
592
592
|
Effect.asVoid,
|
|
593
593
|
PersistenceError.refail,
|
|
594
594
|
withTracerDisabled
|
|
595
|
+
),
|
|
596
|
+
|
|
597
|
+
withTransaction: (effect) =>
|
|
598
|
+
sql.withTransaction(effect).pipe(
|
|
599
|
+
Effect.catchIf(isSqlError, Effect.die)
|
|
595
600
|
)
|
|
596
601
|
})
|
|
597
602
|
}, withTracerDisabled)
|
|
@@ -22,7 +22,8 @@ import { RequestId } from "../../rpc/RpcMessage.ts"
|
|
|
22
22
|
import * as RpcServer from "../../rpc/RpcServer.ts"
|
|
23
23
|
import { AlreadyProcessingMessage, EntityNotAssignedToRunner, MailboxFull, MalformedMessage } from "../ClusterError.ts"
|
|
24
24
|
import * as ClusterMetrics from "../ClusterMetrics.ts"
|
|
25
|
-
import { isUninterruptibleForServer, Persisted } from "../ClusterSchema.ts"
|
|
25
|
+
import { isUninterruptibleForServer, Persisted, WithTransaction } from "../ClusterSchema.ts"
|
|
26
|
+
import * as ClusterSchema from "../ClusterSchema.ts"
|
|
26
27
|
import type { Entity, HandlersFrom } from "../Entity.ts"
|
|
27
28
|
import { CurrentAddress, CurrentRunnerAddress, KeepAliveLatch, KeepAliveRpc, Request } from "../Entity.ts"
|
|
28
29
|
import type { EntityAddress } from "../EntityAddress.ts"
|
|
@@ -187,9 +188,9 @@ export const make = Effect.fnUntraced(function*<
|
|
|
187
188
|
// interrupt.
|
|
188
189
|
if (
|
|
189
190
|
storageEnabled &&
|
|
190
|
-
ServiceMap.get(request.
|
|
191
|
+
ServiceMap.get(request.message.annotations, Persisted) &&
|
|
191
192
|
Exit.hasInterrupts(response.exit) &&
|
|
192
|
-
(isShuttingDown || isUninterruptibleForServer(request.
|
|
193
|
+
(isShuttingDown || isUninterruptibleForServer(request.message.annotations))
|
|
193
194
|
) {
|
|
194
195
|
if (!isShuttingDown) {
|
|
195
196
|
return server.write(0, {
|
|
@@ -395,7 +396,7 @@ export const make = Effect.fnUntraced(function*<
|
|
|
395
396
|
}
|
|
396
397
|
|
|
397
398
|
const rpc = entityRpcs.get(message.envelope.tag)! as any as Rpc.AnyWithProps
|
|
398
|
-
if (!storageEnabled && ServiceMap.get(
|
|
399
|
+
if (!storageEnabled && ServiceMap.get(message.annotations, Persisted)) {
|
|
399
400
|
return Effect.die(
|
|
400
401
|
"EntityManager.sendLocal: Cannot process a persisted message without MessageStorage"
|
|
401
402
|
)
|
|
@@ -448,7 +449,7 @@ export const make = Effect.fnUntraced(function*<
|
|
|
448
449
|
})
|
|
449
450
|
}
|
|
450
451
|
server.activeRequests.set(message.envelope.requestId, entry)
|
|
451
|
-
|
|
452
|
+
let write = server.write(0, {
|
|
452
453
|
...message.envelope,
|
|
453
454
|
id: RequestId(message.envelope.requestId),
|
|
454
455
|
payload: new Request({
|
|
@@ -459,6 +460,10 @@ export const make = Effect.fnUntraced(function*<
|
|
|
459
460
|
)
|
|
460
461
|
})
|
|
461
462
|
})
|
|
463
|
+
if (ServiceMap.get(message.annotations, WithTransaction)) {
|
|
464
|
+
write = options.storage.withTransaction(write)
|
|
465
|
+
}
|
|
466
|
+
return write
|
|
462
467
|
}
|
|
463
468
|
case "IncomingEnvelope": {
|
|
464
469
|
const entry = server.activeRequests.get(message.envelope.requestId)
|
|
@@ -558,6 +563,10 @@ export const make = Effect.fnUntraced(function*<
|
|
|
558
563
|
const rpc = entityRpcs.get(decoded.envelope.tag)!
|
|
559
564
|
return sendLocal(
|
|
560
565
|
new Message.IncomingRequestLocal({
|
|
566
|
+
annotations: ServiceMap.get(rpc.annotations, ClusterSchema.Dynamic)(
|
|
567
|
+
rpc.annotations,
|
|
568
|
+
decoded.envelope as any
|
|
569
|
+
),
|
|
561
570
|
envelope: decoded.envelope,
|
|
562
571
|
lastSentReply: decoded.lastSentReply,
|
|
563
572
|
respond: (reply) =>
|
|
@@ -137,9 +137,9 @@ export * as Template from "./Template.ts"
|
|
|
137
137
|
/**
|
|
138
138
|
* @since 4.0.0
|
|
139
139
|
*/
|
|
140
|
-
export * as
|
|
140
|
+
export * as Url from "./Url.ts"
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* @since 4.0.0
|
|
144
144
|
*/
|
|
145
|
-
export * as
|
|
145
|
+
export * as UrlParams from "./UrlParams.ts"
|
|
@@ -299,7 +299,7 @@ export function asJson(options?: {
|
|
|
299
299
|
export function asFormUrlEncoded(options?: {
|
|
300
300
|
readonly contentType?: string
|
|
301
301
|
}) {
|
|
302
|
-
return <S extends Schema.Top
|
|
302
|
+
return <S extends Schema.Top>(
|
|
303
303
|
self: S
|
|
304
304
|
) => asNonMultipartEncoding(self, { _tag: "FormUrlEncoded", ...options })
|
|
305
305
|
}
|
package/src/unstable/rpc/Rpc.ts
CHANGED
|
@@ -825,10 +825,20 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
|
|
|
825
825
|
Protocol.make(Effect.fnUntraced(function*(writeResponse) {
|
|
826
826
|
const serialization = yield* RpcSerialization.RpcSerialization
|
|
827
827
|
const isFramed = serialization.includesFraming
|
|
828
|
+
const httpClientError = (cause: any) =>
|
|
829
|
+
new RpcClientError({
|
|
830
|
+
reason: HttpClientErrorSchema.fromHttpClientError(cause)
|
|
831
|
+
})
|
|
832
|
+
const protocolDefect = (message: string, cause: unknown) =>
|
|
833
|
+
new RpcClientError({
|
|
834
|
+
reason: new RpcClientDefect({ message, cause })
|
|
835
|
+
})
|
|
836
|
+
const emptyResponseError = (request: FromClientEncoded) =>
|
|
837
|
+
protocolDefect("Received empty HTTP response from RPC server", request)
|
|
828
838
|
|
|
829
|
-
const send = (request: FromClientEncoded)
|
|
839
|
+
const send = Effect.fnUntraced(function*(request: FromClientEncoded) {
|
|
830
840
|
if (request._tag !== "Request") {
|
|
831
|
-
return
|
|
841
|
+
return
|
|
832
842
|
}
|
|
833
843
|
|
|
834
844
|
const parser = serialization.makeUnsafe()
|
|
@@ -838,34 +848,37 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
|
|
|
838
848
|
HttpBody.text(encoded, serialization.contentType) :
|
|
839
849
|
HttpBody.uint8Array(encoded, serialization.contentType)
|
|
840
850
|
|
|
851
|
+
const response = yield* client.post("", { body }).pipe(Effect.mapError(httpClientError))
|
|
852
|
+
|
|
841
853
|
if (!isFramed) {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
)
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
})
|
|
860
|
-
})
|
|
861
|
-
)
|
|
854
|
+
const text = yield* response.text.pipe(Effect.mapError(httpClientError))
|
|
855
|
+
const responses = yield* Effect.try({
|
|
856
|
+
try: () => parser.decode(text),
|
|
857
|
+
catch: (cause) => protocolDefect("Error decoding HTTP response", cause)
|
|
858
|
+
})
|
|
859
|
+
if (!Array.isArray(responses)) {
|
|
860
|
+
return yield* Effect.fail(protocolDefect("Expected an array of responses", responses))
|
|
861
|
+
}
|
|
862
|
+
if (responses.length === 0) {
|
|
863
|
+
return yield* Effect.fail(emptyResponseError(request))
|
|
864
|
+
}
|
|
865
|
+
let i = 0
|
|
866
|
+
return yield* Effect.whileLoop({
|
|
867
|
+
while: () => i < responses.length,
|
|
868
|
+
body: () => writeResponse(responses[i++]),
|
|
869
|
+
step: constVoid
|
|
870
|
+
})
|
|
862
871
|
}
|
|
863
872
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
873
|
+
let hasResponse = false
|
|
874
|
+
yield* Stream.runForEachArray(response.stream, (chunk) =>
|
|
875
|
+
Effect.try({
|
|
876
|
+
try: () => chunk.flatMap(parser.decode) as Array<FromServerEncoded>,
|
|
877
|
+
catch: (cause) => protocolDefect("Error decoding HTTP response", cause)
|
|
878
|
+
}).pipe(
|
|
879
|
+
Effect.flatMap((responses) => {
|
|
868
880
|
if (responses.length === 0) return Effect.void
|
|
881
|
+
hasResponse = true
|
|
869
882
|
let i = 0
|
|
870
883
|
return Effect.whileLoop({
|
|
871
884
|
while: () => i < responses.length,
|
|
@@ -873,14 +886,13 @@ export const makeProtocolHttp = (client: HttpClient.HttpClient): Effect.Effect<
|
|
|
873
886
|
step: constVoid
|
|
874
887
|
})
|
|
875
888
|
})
|
|
876
|
-
)
|
|
877
|
-
|
|
878
|
-
new RpcClientError({
|
|
879
|
-
reason: HttpClientErrorSchema.fromHttpClientError(cause)
|
|
880
|
-
})
|
|
889
|
+
)).pipe(
|
|
890
|
+
Effect.mapError((cause) => cause instanceof RpcClientError ? cause : httpClientError(cause))
|
|
881
891
|
)
|
|
882
|
-
)
|
|
883
|
-
|
|
892
|
+
if (!hasResponse) {
|
|
893
|
+
return yield* Effect.fail(emptyResponseError(request))
|
|
894
|
+
}
|
|
895
|
+
})
|
|
884
896
|
|
|
885
897
|
return {
|
|
886
898
|
send,
|
|
@@ -392,7 +392,7 @@ export const makeChannel = <IE = never>(): Channel.Channel<
|
|
|
392
392
|
/**
|
|
393
393
|
* @since 4.0.0
|
|
394
394
|
*/
|
|
395
|
-
export const defaultCloseCodeIsError = (
|
|
395
|
+
export const defaultCloseCodeIsError = (_code: number) => true
|
|
396
396
|
|
|
397
397
|
/**
|
|
398
398
|
* @since 4.0.0
|
|
@@ -39,6 +39,14 @@ export interface Activity<
|
|
|
39
39
|
readonly successSchema: Success
|
|
40
40
|
readonly errorSchema: Error
|
|
41
41
|
readonly exitSchema: Schema.Exit<Success, Error, Schema.Defect>
|
|
42
|
+
readonly annotations: ServiceMap.ServiceMap<never>
|
|
43
|
+
annotate<I, S>(
|
|
44
|
+
key: ServiceMap.Key<I, S>,
|
|
45
|
+
value: S
|
|
46
|
+
): Activity<Success, Error, R>
|
|
47
|
+
annotateMerge<I>(
|
|
48
|
+
annotations: ServiceMap.ServiceMap<I>
|
|
49
|
+
): Activity<Success, Error, R>
|
|
42
50
|
readonly execute: Effect.Effect<
|
|
43
51
|
Success["Type"],
|
|
44
52
|
Error["Type"],
|
|
@@ -73,6 +81,7 @@ export interface Any {
|
|
|
73
81
|
readonly [TypeId]: typeof TypeId
|
|
74
82
|
readonly name: string
|
|
75
83
|
readonly executeEncoded: Effect.Effect<any, any, any>
|
|
84
|
+
readonly annotations: ServiceMap.ServiceMap<never>
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
/**
|
|
@@ -101,6 +110,7 @@ export const make = <
|
|
|
101
110
|
readonly error?: Error | undefined
|
|
102
111
|
readonly execute: Effect.Effect<Success["Type"], Error["Type"], R>
|
|
103
112
|
readonly interruptRetryPolicy?: Schedule.Schedule<any, Cause.Cause<unknown>> | undefined
|
|
113
|
+
readonly annotations?: ServiceMap.ServiceMap<never> | undefined
|
|
104
114
|
}): Activity<Success, Error, Exclude<R, WorkflowInstance | WorkflowEngine | Scope>> => {
|
|
105
115
|
const successSchema = options.success ?? (Schema.Void as any as Success)
|
|
106
116
|
const errorSchema = options.error ?? (Schema.Never as any as Error)
|
|
@@ -120,6 +130,19 @@ export const make = <
|
|
|
120
130
|
successSchema,
|
|
121
131
|
errorSchema,
|
|
122
132
|
exitSchema: Schema.Exit(successSchemaJson, errorSchemaJson, Schema.Defect),
|
|
133
|
+
annotations: options.annotations ?? ServiceMap.empty(),
|
|
134
|
+
annotate(tag: ServiceMap.Key<any, any>, value: any) {
|
|
135
|
+
return make({
|
|
136
|
+
...options,
|
|
137
|
+
annotations: ServiceMap.add(self.annotations, tag, value)
|
|
138
|
+
})
|
|
139
|
+
},
|
|
140
|
+
annotateMerge(context: ServiceMap.ServiceMap<any>) {
|
|
141
|
+
return make({
|
|
142
|
+
...options,
|
|
143
|
+
annotations: ServiceMap.merge(self.annotations, context)
|
|
144
|
+
})
|
|
145
|
+
},
|
|
123
146
|
execute: executeWithoutInterrupt,
|
|
124
147
|
executeEncoded: Effect.matchEffect(executeWithoutInterrupt, {
|
|
125
148
|
onFailure: (error) => Effect.flatMap(Effect.orDie(Schema.encodeEffect(errorSchemaJson)(error)), Effect.fail),
|