@effect-app/infra 1.23.2 → 1.23.3
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 +11 -0
- package/_cjs/api/internal/events.cjs +2 -1
- package/_cjs/api/internal/events.cjs.map +1 -1
- package/_cjs/api/internal/middlewares.cjs +3 -2
- package/_cjs/api/internal/middlewares.cjs.map +1 -1
- package/_cjs/api/routing/defaultErrorHandler.cjs +3 -2
- package/_cjs/api/routing/defaultErrorHandler.cjs.map +1 -1
- package/_cjs/api/routing/makeRequestHandler.cjs +9 -8
- package/_cjs/api/routing/makeRequestHandler.cjs.map +1 -1
- package/_cjs/errorReporter.cjs +12 -11
- package/_cjs/errorReporter.cjs.map +1 -1
- package/_cjs/logger.cjs +9 -0
- package/_cjs/logger.cjs.map +1 -0
- package/_cjs/services/Emailer/Sendgrid.cjs +6 -5
- package/_cjs/services/Emailer/Sendgrid.cjs.map +1 -1
- package/_cjs/services/Emailer/fake.cjs +3 -2
- package/_cjs/services/Emailer/fake.cjs.map +1 -1
- package/_cjs/services/QueueMaker/SQLQueue.cjs +7 -6
- package/_cjs/services/QueueMaker/SQLQueue.cjs.map +1 -1
- package/_cjs/services/QueueMaker/memQueue.cjs +15 -14
- package/_cjs/services/QueueMaker/memQueue.cjs.map +1 -1
- package/_cjs/services/QueueMaker/sbqueue.cjs +15 -14
- package/_cjs/services/QueueMaker/sbqueue.cjs.map +1 -1
- package/_cjs/services/RepositoryBase.cjs +22 -22
- package/_cjs/services/RepositoryBase.cjs.map +1 -1
- package/_cjs/services/Store/Cosmos/query.cjs +2 -3
- package/_cjs/services/Store/Cosmos/query.cjs.map +1 -1
- package/_cjs/services/Store/Cosmos.cjs +24 -23
- package/_cjs/services/Store/Cosmos.cjs.map +1 -1
- package/_cjs/services/Store/Disk.cjs +6 -6
- package/_cjs/services/Store/Disk.cjs.map +1 -1
- package/_cjs/services/Store/Memory.cjs +7 -6
- package/_cjs/services/Store/Memory.cjs.map +1 -1
- package/_cjs/services/Store/utils.cjs +5 -5
- package/_cjs/services/Store/utils.cjs.map +1 -1
- package/dist/api/internal/events.d.ts.map +1 -1
- package/dist/api/internal/events.js +3 -2
- package/dist/api/internal/middlewares.d.ts.map +1 -1
- package/dist/api/internal/middlewares.js +4 -3
- package/dist/api/routing/defaultErrorHandler.d.ts.map +1 -1
- package/dist/api/routing/defaultErrorHandler.js +4 -3
- package/dist/api/routing/makeRequestHandler.d.ts.map +1 -1
- package/dist/api/routing/makeRequestHandler.js +10 -9
- package/dist/errorReporter.d.ts +1 -1
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +12 -11
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +3 -0
- package/dist/services/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/services/Emailer/Sendgrid.js +8 -7
- package/dist/services/Emailer/fake.d.ts.map +1 -1
- package/dist/services/Emailer/fake.js +5 -4
- package/dist/services/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/SQLQueue.js +9 -8
- package/dist/services/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/memQueue.js +17 -16
- package/dist/services/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/sbqueue.js +17 -16
- package/dist/services/RepositoryBase.d.ts.map +1 -1
- package/dist/services/RepositoryBase.js +23 -23
- package/dist/services/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/services/Store/Cosmos/query.js +3 -4
- package/dist/services/Store/Cosmos.d.ts.map +1 -1
- package/dist/services/Store/Cosmos.js +24 -23
- package/dist/services/Store/Disk.d.ts.map +1 -1
- package/dist/services/Store/Disk.js +8 -8
- package/dist/services/Store/Memory.d.ts.map +1 -1
- package/dist/services/Store/Memory.js +8 -7
- package/dist/services/Store/utils.d.ts.map +1 -1
- package/dist/services/Store/utils.js +5 -5
- package/examples/query.ts +3 -3
- package/package.json +15 -5
- package/src/api/internal/events.ts +2 -1
- package/src/api/internal/middlewares.ts +3 -2
- package/src/api/routing/defaultErrorHandler.ts +3 -2
- package/src/api/routing/makeRequestHandler.ts +9 -8
- package/src/api/writeDocs.ts.bak +1 -1
- package/src/errorReporter.ts +31 -33
- package/src/logger.ts +3 -0
- package/src/services/Emailer/Sendgrid.ts +14 -12
- package/src/services/Emailer/fake.ts +4 -3
- package/src/services/QueueMaker/SQLQueue.ts +18 -19
- package/src/services/QueueMaker/memQueue.ts +33 -36
- package/src/services/QueueMaker/sbqueue.ts +38 -41
- package/src/services/RepositoryBase.ts +40 -43
- package/src/services/Store/Cosmos/query.ts +6 -5
- package/src/services/Store/Cosmos.ts +75 -90
- package/src/services/Store/Disk.ts +12 -14
- package/src/services/Store/Memory.ts +7 -6
- package/src/services/Store/utils.ts +10 -14
- package/test/query.test.ts +56 -61
|
@@ -15,6 +15,7 @@ import type { HttpServerError } from "effect-app/http"
|
|
|
15
15
|
import { HttpBody, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
16
16
|
import { NonEmptyString255 } from "effect-app/schema"
|
|
17
17
|
import type { REST } from "effect-app/schema"
|
|
18
|
+
import { InfraLogger } from "src/logger.js"
|
|
18
19
|
import { updateRequestContext } from "../setupRequest.js"
|
|
19
20
|
import { makeRequestParsers, parseRequestParams } from "./base.js"
|
|
20
21
|
import type { RequestHandler, RequestHandlerBase } from "./base.js"
|
|
@@ -170,19 +171,19 @@ export function makeRequestHandler<
|
|
|
170
171
|
)
|
|
171
172
|
|
|
172
173
|
return Effect
|
|
173
|
-
.gen(function*(
|
|
174
|
-
const req = yield*
|
|
174
|
+
.gen(function*() {
|
|
175
|
+
const req = yield* HttpServerRequest.HttpServerRequest
|
|
175
176
|
const res = HttpServerResponse
|
|
176
177
|
.empty()
|
|
177
178
|
.pipe((_) => req.method === "GET" ? HttpServerResponse.setHeader(_, "Cache-Control", "no-store") : _)
|
|
178
179
|
|
|
179
|
-
const pars = yield*
|
|
180
|
+
const pars = yield* getParams
|
|
180
181
|
|
|
181
|
-
const settings = yield*
|
|
182
|
+
const settings = yield* FiberRef.get(RequestSettings)
|
|
182
183
|
|
|
183
184
|
const eff =
|
|
184
185
|
// TODO: we don;t have access to user id here cause context is not yet created
|
|
185
|
-
|
|
186
|
+
InfraLogger
|
|
186
187
|
.logInfo("Incoming request")
|
|
187
188
|
.pipe(
|
|
188
189
|
Effect.annotateLogs({
|
|
@@ -281,7 +282,7 @@ export function makeRequestHandler<
|
|
|
281
282
|
}),
|
|
282
283
|
Effect.suspend(() => {
|
|
283
284
|
const headers = res.headers
|
|
284
|
-
return
|
|
285
|
+
return InfraLogger
|
|
285
286
|
.logError("Finished request", cause)
|
|
286
287
|
.pipe(Effect.annotateLogs({
|
|
287
288
|
method: req.method,
|
|
@@ -312,7 +313,7 @@ export function makeRequestHandler<
|
|
|
312
313
|
),
|
|
313
314
|
Effect
|
|
314
315
|
.tap((res) =>
|
|
315
|
-
|
|
316
|
+
InfraLogger
|
|
316
317
|
.logInfo("Finished request")
|
|
317
318
|
.pipe(Effect.annotateLogs({
|
|
318
319
|
method: req.method,
|
|
@@ -327,7 +328,7 @@ export function makeRequestHandler<
|
|
|
327
328
|
)
|
|
328
329
|
)
|
|
329
330
|
|
|
330
|
-
return yield*
|
|
331
|
+
return yield* eff
|
|
331
332
|
})
|
|
332
333
|
.pipe((_) =>
|
|
333
334
|
updateRequestContext(
|
package/src/api/writeDocs.ts.bak
CHANGED
|
@@ -27,5 +27,5 @@ export function writeOpenapiDocsI(rdescs: readonly RouteDescriptorAny[]) {
|
|
|
27
27
|
]
|
|
28
28
|
}))
|
|
29
29
|
.flatMap((_) => writeTextFile("./openapi.json", JSON.stringify(_, undefined, 2)).orDie)
|
|
30
|
-
.flatMap(() =>
|
|
30
|
+
.flatMap(() => InfraLogger.logDebug("OpenAPI spec written to './openapi.json'"))
|
|
31
31
|
}
|
package/src/errorReporter.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { dropUndefined } from "@effect-app/core/utils"
|
|
|
2
2
|
import * as Sentry from "@sentry/node"
|
|
3
3
|
import { Cause, Effect, Option } from "effect-app"
|
|
4
4
|
import { annotateSpanWithError, CauseException, ErrorReported } from "./errors.js"
|
|
5
|
+
import { InfraLogger } from "./logger.js"
|
|
5
6
|
import { RequestContextContainer } from "./services/RequestContextContainer.js"
|
|
6
7
|
|
|
7
8
|
const tryToJson = <T>(error: CauseException<T>) => {
|
|
@@ -24,28 +25,27 @@ export function reportError(
|
|
|
24
25
|
name: string
|
|
25
26
|
) {
|
|
26
27
|
return (cause: Cause<unknown>, extras?: Record<string, unknown>) =>
|
|
27
|
-
Effect.gen(function*(
|
|
28
|
-
yield*
|
|
28
|
+
Effect.gen(function*() {
|
|
29
|
+
yield* annotateSpanWithError(cause, name)
|
|
29
30
|
if (Cause.isInterrupted(cause)) {
|
|
30
|
-
yield*
|
|
31
|
+
yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {})))
|
|
31
32
|
return
|
|
32
33
|
}
|
|
33
34
|
const error = new CauseException(cause, name)
|
|
34
35
|
|
|
35
|
-
yield*
|
|
36
|
-
yield*
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
36
|
+
yield* reportSentry(error, extras)
|
|
37
|
+
yield* InfraLogger
|
|
38
|
+
.logError("Reporting error", cause)
|
|
39
|
+
.pipe(
|
|
40
|
+
Effect.annotateLogs(dropUndefined({
|
|
41
|
+
extras,
|
|
42
|
+
__cause__: tryToJson(error),
|
|
43
|
+
__error_name__: name
|
|
44
|
+
})),
|
|
45
|
+
Effect.catchAllCause((cause) => InfraLogger.logError("Failed to log error", cause)),
|
|
46
|
+
Effect.catchAllCause(() => InfraLogger.logError("Failed to log error cause"))
|
|
47
|
+
)
|
|
48
|
+
|
|
49
49
|
error[ErrorReported] = true
|
|
50
50
|
return error
|
|
51
51
|
})
|
|
@@ -69,25 +69,23 @@ export function logError<E>(
|
|
|
69
69
|
name: string
|
|
70
70
|
) {
|
|
71
71
|
return (cause: Cause<E>, extras?: Record<string, unknown>) =>
|
|
72
|
-
Effect.gen(function*(
|
|
72
|
+
Effect.gen(function*() {
|
|
73
73
|
if (Cause.isInterrupted(cause)) {
|
|
74
|
-
yield*
|
|
74
|
+
yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras })))
|
|
75
75
|
return
|
|
76
76
|
}
|
|
77
77
|
const error = new CauseException(cause, name)
|
|
78
|
-
yield*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
)
|
|
90
|
-
)
|
|
78
|
+
yield* InfraLogger
|
|
79
|
+
.logWarning("Logging error", cause)
|
|
80
|
+
.pipe(
|
|
81
|
+
Effect.annotateLogs(dropUndefined({
|
|
82
|
+
extras,
|
|
83
|
+
__cause__: tryToJson(error),
|
|
84
|
+
__error_name__: name
|
|
85
|
+
})),
|
|
86
|
+
Effect.catchAllCause((cause) => InfraLogger.logError("Failed to log error", cause)),
|
|
87
|
+
Effect.catchAllCause(() => InfraLogger.logError("Failed to log error cause"))
|
|
88
|
+
)
|
|
91
89
|
})
|
|
92
90
|
}
|
|
93
91
|
|
|
@@ -96,7 +94,7 @@ export function captureException(error: unknown) {
|
|
|
96
94
|
console.error(error)
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
export function reportMessage(message: string, extras?: Record<string, unknown>
|
|
97
|
+
export function reportMessage(message: string, extras?: Record<string, unknown>) {
|
|
100
98
|
return RequestContextContainer.getOption.pipe(Effect.map((ctx) => {
|
|
101
99
|
const context = Option.getOrUndefined(ctx)
|
|
102
100
|
const scope = new Sentry.Scope()
|
package/src/logger.ts
ADDED
|
@@ -2,6 +2,7 @@ import { dropUndefinedT } from "@effect-app/core/utils"
|
|
|
2
2
|
import type { EmailData } from "@sendgrid/helpers/classes/email-address.js"
|
|
3
3
|
import sgMail from "@sendgrid/mail"
|
|
4
4
|
import { Array, Effect, Equivalence, Secret } from "effect-app"
|
|
5
|
+
import { InfraLogger } from "src/logger.js"
|
|
5
6
|
import { inspect } from "util"
|
|
6
7
|
import { Emailer } from "./service.js"
|
|
7
8
|
import type { EmailMsg, EmailMsgOptionalFrom, SendgridConfig } from "./service.js"
|
|
@@ -12,7 +13,7 @@ const makeSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subjectPr
|
|
|
12
13
|
|
|
13
14
|
return Emailer.of({
|
|
14
15
|
sendMail(msg_: EmailMsgOptionalFrom) {
|
|
15
|
-
return Effect.gen(function*(
|
|
16
|
+
return Effect.gen(function*() {
|
|
16
17
|
const msg: EmailMsg = dropUndefinedT({
|
|
17
18
|
...msg_,
|
|
18
19
|
from: msg_.from ?? defaultFrom,
|
|
@@ -22,16 +23,17 @@ const makeSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subjectPr
|
|
|
22
23
|
|
|
23
24
|
const renderedMsg_ = render(msg)
|
|
24
25
|
const renderedMsg = { ...renderedMsg_, subject: `${subjectPrefix}${renderedMsg_.subject}` }
|
|
25
|
-
yield*
|
|
26
|
+
yield* InfraLogger.logDebug("Sending email").pipe(Effect.annotateLogs("msg", inspect(renderedMsg, false, 5)))
|
|
26
27
|
|
|
27
|
-
const ret = yield*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
const ret = yield* Effect.async<
|
|
29
|
+
[sgMail.ClientResponse, Record<string, unknown>],
|
|
30
|
+
Error | sgMail.ResponseError
|
|
31
|
+
>(
|
|
32
|
+
(cb) =>
|
|
33
|
+
void sgMail.send(renderedMsg, false, (err, result) =>
|
|
34
|
+
err
|
|
35
|
+
? cb(Effect.fail(err))
|
|
36
|
+
: cb(Effect.sync(() => result)))
|
|
35
37
|
)
|
|
36
38
|
|
|
37
39
|
// const event = {
|
|
@@ -40,8 +42,8 @@ const makeSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subjectPr
|
|
|
40
42
|
// templateId: msg.templateId
|
|
41
43
|
// }
|
|
42
44
|
// }
|
|
43
|
-
// yield*
|
|
44
|
-
// const { trackEvent } = yield*
|
|
45
|
+
// yield* InfraLogger.logDebug("Tracking email event").annotateLogs("event", event.$$.pretty)
|
|
46
|
+
// const { trackEvent } = yield* AiContextService
|
|
45
47
|
// trackEvent(event)
|
|
46
48
|
return ret
|
|
47
49
|
})
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Effect } from "effect-app"
|
|
2
2
|
import { pretty } from "effect-app/utils"
|
|
3
|
+
import { InfraLogger } from "src/logger.js"
|
|
3
4
|
import { Emailer } from "./service.js"
|
|
4
5
|
|
|
5
|
-
const makeFake =
|
|
6
|
-
.
|
|
6
|
+
const makeFake = InfraLogger
|
|
7
|
+
.logInfo("FAKE Emailer Service enabled")
|
|
7
8
|
.pipe(Effect.map(() =>
|
|
8
9
|
Emailer.of({
|
|
9
10
|
sendMail(msg) {
|
|
10
|
-
return
|
|
11
|
+
return InfraLogger
|
|
11
12
|
.logDebug(`Fake send mail`)
|
|
12
13
|
.pipe(Effect.annotateLogs("msg", pretty(msg)))
|
|
13
14
|
}
|
|
@@ -10,6 +10,7 @@ import { Effect, Fiber, Option, S, Tracer } from "effect-app"
|
|
|
10
10
|
import { RequestId } from "effect-app/ids"
|
|
11
11
|
import { NonEmptyString255 } from "effect-app/schema"
|
|
12
12
|
import { pretty } from "effect-app/utils"
|
|
13
|
+
import { InfraLogger } from "src/logger.js"
|
|
13
14
|
|
|
14
15
|
export const QueueId = S.Number.pipe(S.brand("QueueId"))
|
|
15
16
|
export type QueueId = typeof QueueId.Type
|
|
@@ -113,23 +114,21 @@ export function makeSQLQueue<
|
|
|
113
114
|
return {
|
|
114
115
|
publish: (...messages) =>
|
|
115
116
|
Effect
|
|
116
|
-
.gen(function*(
|
|
117
|
-
const requestContext = yield*
|
|
118
|
-
const span = yield*
|
|
119
|
-
return yield*
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
(m
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
132
|
-
)
|
|
117
|
+
.gen(function*() {
|
|
118
|
+
const requestContext = yield* rcc.requestContext
|
|
119
|
+
const span = yield* Effect.serviceOption(Tracer.ParentSpan)
|
|
120
|
+
return yield* Effect
|
|
121
|
+
.forEach(
|
|
122
|
+
messages,
|
|
123
|
+
(m) =>
|
|
124
|
+
q.offer(m, {
|
|
125
|
+
requestContext: new RequestContext(requestContext), // workaround Schema expecting exact class
|
|
126
|
+
span: Option.getOrUndefined(span)
|
|
127
|
+
}),
|
|
128
|
+
{
|
|
129
|
+
discard: true
|
|
130
|
+
}
|
|
131
|
+
)
|
|
133
132
|
})
|
|
134
133
|
.pipe(
|
|
135
134
|
Effect.withSpan("queue.publish: " + queueName, {
|
|
@@ -149,8 +148,8 @@ export function makeSQLQueue<
|
|
|
149
148
|
.succeed(msg)
|
|
150
149
|
.pipe(Effect
|
|
151
150
|
.flatMap(({ body, meta }) => {
|
|
152
|
-
let effect =
|
|
153
|
-
.
|
|
151
|
+
let effect = InfraLogger
|
|
152
|
+
.logInfo(`[${queueDrainName}] Processing incoming message`)
|
|
154
153
|
.pipe(
|
|
155
154
|
Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
|
|
156
155
|
Effect.zipRight(handleEvent(body)),
|
|
@@ -5,6 +5,7 @@ import { Tracer } from "effect"
|
|
|
5
5
|
import { Effect, Fiber, flow, Option, S } from "effect-app"
|
|
6
6
|
import { RequestId } from "effect-app/ids"
|
|
7
7
|
import { pretty } from "effect-app/utils"
|
|
8
|
+
import { InfraLogger } from "src/logger.js"
|
|
8
9
|
import { setupRequestContext } from "../../api/setupRequest.js"
|
|
9
10
|
import { RequestContextContainer } from "../RequestContextContainer.js"
|
|
10
11
|
import { reportNonInterruptedFailure } from "./errors.js"
|
|
@@ -24,11 +25,11 @@ export function makeMemQueue<
|
|
|
24
25
|
schema: S.Schema<Evt, EvtE>,
|
|
25
26
|
drainSchema: S.Schema<DrainEvt, DrainEvtE>
|
|
26
27
|
) {
|
|
27
|
-
return Effect.gen(function*(
|
|
28
|
-
const mem = yield*
|
|
29
|
-
const q = yield*
|
|
30
|
-
const qDrain = yield*
|
|
31
|
-
const rcc = yield*
|
|
28
|
+
return Effect.gen(function*() {
|
|
29
|
+
const mem = yield* MemQueue
|
|
30
|
+
const q = yield* mem.getOrCreateQueue(queueName)
|
|
31
|
+
const qDrain = yield* mem.getOrCreateQueue(queueDrainName)
|
|
32
|
+
const rcc = yield* RequestContextContainer
|
|
32
33
|
|
|
33
34
|
const wireSchema = S.Struct({ body: schema, meta: QueueMeta })
|
|
34
35
|
const drainW = S.Struct({ body: drainSchema, meta: QueueMeta })
|
|
@@ -37,21 +38,19 @@ export function makeMemQueue<
|
|
|
37
38
|
return {
|
|
38
39
|
publish: (...messages) =>
|
|
39
40
|
Effect
|
|
40
|
-
.gen(function*(
|
|
41
|
-
const requestContext = yield*
|
|
42
|
-
const span = yield*
|
|
43
|
-
return yield*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
), { discard: true })
|
|
54
|
-
)
|
|
41
|
+
.gen(function*() {
|
|
42
|
+
const requestContext = yield* rcc.requestContext
|
|
43
|
+
const span = yield* Effect.serviceOption(Tracer.ParentSpan)
|
|
44
|
+
return yield* Effect
|
|
45
|
+
.forEach(messages, (m) =>
|
|
46
|
+
// we JSON encode, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
|
|
47
|
+
S.encode(wireSchema)({ body: m, meta: { requestContext, span: Option.getOrUndefined(span) } }).pipe(
|
|
48
|
+
Effect.orDie,
|
|
49
|
+
Effect
|
|
50
|
+
.andThen(JSON.stringify),
|
|
51
|
+
// .tap((msg) => info("Publishing Mem Message: " + utils.inspect(msg)))
|
|
52
|
+
Effect.flatMap((_) => q.offer(_))
|
|
53
|
+
), { discard: true })
|
|
55
54
|
})
|
|
56
55
|
.pipe(
|
|
57
56
|
Effect.withSpan("queue.publish: " + queueName, {
|
|
@@ -64,7 +63,7 @@ export function makeMemQueue<
|
|
|
64
63
|
handleEvent: (ks: DrainEvt) => Effect<void, DrainE, DrainR>,
|
|
65
64
|
sessionId?: string
|
|
66
65
|
) =>
|
|
67
|
-
Effect.gen(function*(
|
|
66
|
+
Effect.gen(function*() {
|
|
68
67
|
const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName })
|
|
69
68
|
const processMessage = (msg: string) =>
|
|
70
69
|
// we JSON parse, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
|
|
@@ -75,8 +74,8 @@ export function makeMemQueue<
|
|
|
75
74
|
Effect.orDie,
|
|
76
75
|
Effect
|
|
77
76
|
.flatMap(({ body, meta }) => {
|
|
78
|
-
let effect =
|
|
79
|
-
.
|
|
77
|
+
let effect = InfraLogger
|
|
78
|
+
.logInfo(`[${queueDrainName}] Processing incoming message`)
|
|
80
79
|
.pipe(
|
|
81
80
|
Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
|
|
82
81
|
Effect.zipRight(handleEvent(body)),
|
|
@@ -107,19 +106,17 @@ export function makeMemQueue<
|
|
|
107
106
|
return effect
|
|
108
107
|
})
|
|
109
108
|
)
|
|
110
|
-
return yield*
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.
|
|
114
|
-
Effect.flatMap(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
)
|
|
109
|
+
return yield* qDrain
|
|
110
|
+
.take
|
|
111
|
+
.pipe(
|
|
112
|
+
Effect.flatMap((x) =>
|
|
113
|
+
processMessage(x).pipe(Effect.uninterruptible, Effect.fork, Effect.flatMap(Fiber.join))
|
|
114
|
+
),
|
|
115
|
+
// TODO: normally a failed item would be returned to the queue and retried up to X times.
|
|
116
|
+
// .flatMap(_ => _._tag === "Failure" && !isInterrupted ? qDrain.offer(x) : Effect.unit) // TODO: retry count tracking and max retries.
|
|
117
|
+
silenceAndReportError,
|
|
118
|
+
Effect.forever
|
|
119
|
+
)
|
|
123
120
|
})
|
|
124
121
|
} satisfies QueueBase<Evt, DrainEvt>
|
|
125
122
|
})
|
|
@@ -13,6 +13,7 @@ import { RequestId } from "effect-app/ids"
|
|
|
13
13
|
import type { StringId } from "effect-app/schema"
|
|
14
14
|
import { NonEmptyString255 } from "effect-app/schema"
|
|
15
15
|
import { pretty } from "effect-app/utils"
|
|
16
|
+
import { InfraLogger } from "src/logger.js"
|
|
16
17
|
import { setupRequestContext } from "../../api/setupRequest.js"
|
|
17
18
|
import { RequestContextContainer } from "../RequestContextContainer.js"
|
|
18
19
|
import { reportNonInterruptedFailure, reportNonInterruptedFailureCause, reportQueueError } from "./errors.js"
|
|
@@ -39,16 +40,16 @@ export function makeServiceBusQueue<
|
|
|
39
40
|
const drainW = S.Struct({ body: drainSchema, meta: QueueMeta })
|
|
40
41
|
const parseDrain = flow(S.decodeUnknown(drainW), Effect.orDie)
|
|
41
42
|
|
|
42
|
-
return Effect.gen(function*(
|
|
43
|
-
const s = yield*
|
|
44
|
-
const receiver = yield*
|
|
43
|
+
return Effect.gen(function*() {
|
|
44
|
+
const s = yield* Sender
|
|
45
|
+
const receiver = yield* ServiceBusReceiverFactory
|
|
45
46
|
const silenceAndReportError = reportNonInterruptedFailure({ name: "ServiceBusQueue.drain." + queueDrainName })
|
|
46
47
|
const reportError = reportNonInterruptedFailureCause({ name: "ServiceBusQueue.drain." + queueDrainName })
|
|
47
|
-
const rcc = yield*
|
|
48
|
+
const rcc = yield* RequestContextContainer
|
|
48
49
|
|
|
49
50
|
// TODO: or do async?
|
|
50
51
|
// This will make sure that the host receives the error (MainFiberSet.join), who will then interrupt everything and commence a shutdown and restart of app
|
|
51
|
-
// const deferred = yield*
|
|
52
|
+
// const deferred = yield* Deferred.make<never, ServiceBusError | Error>()
|
|
52
53
|
|
|
53
54
|
return {
|
|
54
55
|
drain: <DrainE, DrainR>(
|
|
@@ -56,7 +57,7 @@ export function makeServiceBusQueue<
|
|
|
56
57
|
sessionId?: string
|
|
57
58
|
) =>
|
|
58
59
|
Effect
|
|
59
|
-
.gen(function*(
|
|
60
|
+
.gen(function*() {
|
|
60
61
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
62
|
function processMessage(messageBody: any) {
|
|
62
63
|
return Effect
|
|
@@ -66,8 +67,8 @@ export function makeServiceBusQueue<
|
|
|
66
67
|
Effect.orDie,
|
|
67
68
|
Effect
|
|
68
69
|
.flatMap(({ body, meta }) => {
|
|
69
|
-
let effect =
|
|
70
|
-
.
|
|
70
|
+
let effect = InfraLogger
|
|
71
|
+
.logInfo(`[${queueDrainName}] Processing incoming message`)
|
|
71
72
|
.pipe(
|
|
72
73
|
Effect.annotateLogs({
|
|
73
74
|
body: pretty(body),
|
|
@@ -113,46 +114,42 @@ export function makeServiceBusQueue<
|
|
|
113
114
|
)
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
return yield*
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
.pipe(Effect.provideService(ServiceBusReceiverFactory, receiver))
|
|
127
|
-
)
|
|
117
|
+
return yield* subscribe({
|
|
118
|
+
processMessage: (x) => processMessage(x.body).pipe(Effect.uninterruptible),
|
|
119
|
+
processError: (err) => reportQueueError(Cause.fail(err.error))
|
|
120
|
+
// Deferred.completeWith(
|
|
121
|
+
// deferred,
|
|
122
|
+
// reportFatalQueueError(Cause.fail(err.error))
|
|
123
|
+
// .pipe(Effect.andThen(Effect.fail(err.error)))
|
|
124
|
+
// )
|
|
125
|
+
}, sessionId)
|
|
126
|
+
.pipe(Effect.provideService(ServiceBusReceiverFactory, receiver))
|
|
128
127
|
})
|
|
129
128
|
// .pipe(Effect.andThen(Deferred.await(deferred).pipe(Effect.orDie))),
|
|
130
129
|
.pipe(Effect.andThen(Effect.never)),
|
|
131
130
|
|
|
132
131
|
publish: (...messages) =>
|
|
133
132
|
Effect
|
|
134
|
-
.gen(function*(
|
|
135
|
-
const requestContext = yield*
|
|
136
|
-
const span = yield*
|
|
137
|
-
return yield*
|
|
138
|
-
|
|
139
|
-
.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
{ abortSignal }
|
|
153
|
-
)
|
|
133
|
+
.gen(function*() {
|
|
134
|
+
const requestContext = yield* rcc.requestContext
|
|
135
|
+
const span = yield* Effect.serviceOption(Tracer.ParentSpan)
|
|
136
|
+
return yield* Effect
|
|
137
|
+
.promise((abortSignal) =>
|
|
138
|
+
s.sendMessages(
|
|
139
|
+
messages.map((m) => ({
|
|
140
|
+
body: JSON.stringify(
|
|
141
|
+
S.encodeSync(wireSchema)({
|
|
142
|
+
body: m,
|
|
143
|
+
meta: { requestContext, span: Option.getOrUndefined(span) }
|
|
144
|
+
})
|
|
145
|
+
),
|
|
146
|
+
messageId: m.id, /* correllationid: requestId */
|
|
147
|
+
contentType: "application/json",
|
|
148
|
+
sessionId: "sessionId" in m ? m.sessionId : undefined
|
|
149
|
+
})),
|
|
150
|
+
{ abortSignal }
|
|
154
151
|
)
|
|
155
|
-
|
|
152
|
+
)
|
|
156
153
|
})
|
|
157
154
|
.pipe(Effect.withSpan("queue.publish: " + queueName, {
|
|
158
155
|
captureStackTrace: false,
|