@effect-app/infra 4.0.0-beta.20 → 4.0.0-beta.201

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.
Files changed (305) hide show
  1. package/CHANGELOG.md +1410 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +15 -7
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +10 -12
  6. package/dist/Emailer/Sendgrid.d.ts +14 -14
  7. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  8. package/dist/Emailer/Sendgrid.js +16 -15
  9. package/dist/Emailer/fake.d.ts +1 -1
  10. package/dist/Emailer/service.d.ts +10 -4
  11. package/dist/Emailer/service.d.ts.map +1 -1
  12. package/dist/Emailer/service.js +3 -3
  13. package/dist/Emailer.d.ts +1 -1
  14. package/dist/MainFiberSet.d.ts +9 -9
  15. package/dist/MainFiberSet.d.ts.map +1 -1
  16. package/dist/MainFiberSet.js +3 -3
  17. package/dist/Model/Repository/Registry.d.ts +20 -0
  18. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  19. package/dist/Model/Repository/Registry.js +17 -0
  20. package/dist/Model/Repository/ext.d.ts +33 -15
  21. package/dist/Model/Repository/ext.d.ts.map +1 -1
  22. package/dist/Model/Repository/ext.js +54 -2
  23. package/dist/Model/Repository/internal/internal.d.ts +6 -6
  24. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  25. package/dist/Model/Repository/internal/internal.js +43 -32
  26. package/dist/Model/Repository/legacy.d.ts +1 -1
  27. package/dist/Model/Repository/makeRepo.d.ts +7 -6
  28. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.js +5 -1
  30. package/dist/Model/Repository/service.d.ts +28 -23
  31. package/dist/Model/Repository/service.d.ts.map +1 -1
  32. package/dist/Model/Repository/validation.d.ts +142 -17
  33. package/dist/Model/Repository/validation.d.ts.map +1 -1
  34. package/dist/Model/Repository/validation.js +5 -5
  35. package/dist/Model/Repository.d.ts +2 -1
  36. package/dist/Model/Repository.d.ts.map +1 -1
  37. package/dist/Model/Repository.js +2 -1
  38. package/dist/Model/dsl.d.ts +4 -4
  39. package/dist/Model/dsl.d.ts.map +1 -1
  40. package/dist/Model/filter/filterApi.d.ts +5 -5
  41. package/dist/Model/filter/filterApi.d.ts.map +1 -1
  42. package/dist/Model/filter/types/errors.d.ts +1 -1
  43. package/dist/Model/filter/types/fields.d.ts +1 -1
  44. package/dist/Model/filter/types/path/common.d.ts +1 -1
  45. package/dist/Model/filter/types/path/eager.d.ts +1 -1
  46. package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
  47. package/dist/Model/filter/types/path/eager.js +1 -1
  48. package/dist/Model/filter/types/path/index.d.ts +1 -1
  49. package/dist/Model/filter/types/utils.d.ts +1 -1
  50. package/dist/Model/filter/types/validator.d.ts +1 -1
  51. package/dist/Model/filter/types.d.ts +1 -1
  52. package/dist/Model/query/dsl.d.ts +16 -16
  53. package/dist/Model/query/dsl.d.ts.map +1 -1
  54. package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
  55. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  56. package/dist/Model/query/new-kid-interpreter.js +3 -3
  57. package/dist/Model/query.d.ts +1 -1
  58. package/dist/Model.d.ts +2 -1
  59. package/dist/Model.d.ts.map +1 -1
  60. package/dist/Model.js +2 -1
  61. package/dist/QueueMaker/SQLQueue.d.ts +5 -7
  62. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  63. package/dist/QueueMaker/SQLQueue.js +105 -114
  64. package/dist/QueueMaker/errors.d.ts +2 -2
  65. package/dist/QueueMaker/errors.d.ts.map +1 -1
  66. package/dist/QueueMaker/memQueue.d.ts +7 -4
  67. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  68. package/dist/QueueMaker/memQueue.js +51 -62
  69. package/dist/QueueMaker/sbqueue.d.ts +6 -3
  70. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  71. package/dist/QueueMaker/sbqueue.js +37 -53
  72. package/dist/QueueMaker/service.d.ts +1 -1
  73. package/dist/RequestContext.d.ts +112 -26
  74. package/dist/RequestContext.d.ts.map +1 -1
  75. package/dist/RequestContext.js +7 -8
  76. package/dist/RequestFiberSet.d.ts +7 -7
  77. package/dist/RequestFiberSet.d.ts.map +1 -1
  78. package/dist/RequestFiberSet.js +5 -5
  79. package/dist/Store/ContextMapContainer.d.ts +19 -3
  80. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  81. package/dist/Store/ContextMapContainer.js +13 -3
  82. package/dist/Store/Cosmos/query.d.ts +1 -1
  83. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  84. package/dist/Store/Cosmos/query.js +10 -12
  85. package/dist/Store/Cosmos.d.ts +1 -1
  86. package/dist/Store/Cosmos.d.ts.map +1 -1
  87. package/dist/Store/Cosmos.js +318 -240
  88. package/dist/Store/Disk.d.ts +2 -2
  89. package/dist/Store/Disk.d.ts.map +1 -1
  90. package/dist/Store/Disk.js +25 -22
  91. package/dist/Store/Memory.d.ts +4 -4
  92. package/dist/Store/Memory.d.ts.map +1 -1
  93. package/dist/Store/Memory.js +27 -22
  94. package/dist/Store/SQL/Pg.d.ts +4 -0
  95. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  96. package/dist/Store/SQL/Pg.js +189 -0
  97. package/dist/Store/SQL/query.d.ts +38 -0
  98. package/dist/Store/SQL/query.d.ts.map +1 -0
  99. package/dist/Store/SQL/query.js +367 -0
  100. package/dist/Store/SQL.d.ts +20 -0
  101. package/dist/Store/SQL.d.ts.map +1 -0
  102. package/dist/Store/SQL.js +381 -0
  103. package/dist/Store/codeFilter.d.ts +1 -1
  104. package/dist/Store/codeFilter.d.ts.map +1 -1
  105. package/dist/Store/codeFilter.js +2 -1
  106. package/dist/Store/index.d.ts +5 -2
  107. package/dist/Store/index.d.ts.map +1 -1
  108. package/dist/Store/index.js +15 -3
  109. package/dist/Store/service.d.ts +18 -7
  110. package/dist/Store/service.d.ts.map +1 -1
  111. package/dist/Store/service.js +24 -6
  112. package/dist/Store/utils.d.ts +1 -1
  113. package/dist/Store/utils.d.ts.map +1 -1
  114. package/dist/Store/utils.js +3 -4
  115. package/dist/Store.d.ts +1 -1
  116. package/dist/adapters/SQL/Model.d.ts +28 -42
  117. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  118. package/dist/adapters/SQL/Model.js +2 -2
  119. package/dist/adapters/SQL.d.ts +1 -1
  120. package/dist/adapters/ServiceBus.d.ts +11 -11
  121. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  122. package/dist/adapters/ServiceBus.js +13 -15
  123. package/dist/adapters/cosmos-client.d.ts +3 -3
  124. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  125. package/dist/adapters/cosmos-client.js +3 -3
  126. package/dist/adapters/index.d.ts +8 -2
  127. package/dist/adapters/index.d.ts.map +1 -1
  128. package/dist/adapters/index.js +8 -2
  129. package/dist/adapters/logger.d.ts +2 -2
  130. package/dist/adapters/logger.d.ts.map +1 -1
  131. package/dist/adapters/memQueue.d.ts +3 -3
  132. package/dist/adapters/memQueue.d.ts.map +1 -1
  133. package/dist/adapters/memQueue.js +3 -3
  134. package/dist/adapters/mongo-client.d.ts +3 -3
  135. package/dist/adapters/mongo-client.d.ts.map +1 -1
  136. package/dist/adapters/mongo-client.js +3 -3
  137. package/dist/adapters/redis-client.d.ts +3 -3
  138. package/dist/adapters/redis-client.d.ts.map +1 -1
  139. package/dist/adapters/redis-client.js +3 -3
  140. package/dist/api/ContextProvider.d.ts +8 -8
  141. package/dist/api/ContextProvider.d.ts.map +1 -1
  142. package/dist/api/ContextProvider.js +6 -6
  143. package/dist/api/codec.d.ts +1 -1
  144. package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
  145. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  146. package/dist/api/internal/RequestContextMiddleware.js +2 -2
  147. package/dist/api/internal/auth.d.ts +44 -6
  148. package/dist/api/internal/auth.d.ts.map +1 -1
  149. package/dist/api/internal/auth.js +160 -29
  150. package/dist/api/internal/events.d.ts +3 -3
  151. package/dist/api/internal/events.d.ts.map +1 -1
  152. package/dist/api/internal/events.js +9 -7
  153. package/dist/api/internal/health.d.ts +1 -1
  154. package/dist/api/layerUtils.d.ts +6 -6
  155. package/dist/api/layerUtils.d.ts.map +1 -1
  156. package/dist/api/layerUtils.js +5 -5
  157. package/dist/api/middlewares.d.ts +1 -1
  158. package/dist/api/reportError.d.ts +1 -1
  159. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
  160. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  161. package/dist/api/routing/middleware/middleware.d.ts +39 -3
  162. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  163. package/dist/api/routing/middleware/middleware.js +46 -14
  164. package/dist/api/routing/middleware.d.ts +1 -2
  165. package/dist/api/routing/middleware.d.ts.map +1 -1
  166. package/dist/api/routing/middleware.js +1 -2
  167. package/dist/api/routing/schema/jwt.d.ts +1 -1
  168. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  169. package/dist/api/routing/tsort.d.ts +1 -1
  170. package/dist/api/routing/tsort.d.ts.map +1 -1
  171. package/dist/api/routing/utils.d.ts +3 -3
  172. package/dist/api/routing/utils.d.ts.map +1 -1
  173. package/dist/api/routing.d.ts +25 -26
  174. package/dist/api/routing.d.ts.map +1 -1
  175. package/dist/api/routing.js +99 -35
  176. package/dist/api/setupRequest.d.ts +8 -5
  177. package/dist/api/setupRequest.d.ts.map +1 -1
  178. package/dist/api/setupRequest.js +12 -7
  179. package/dist/api/util.d.ts +1 -1
  180. package/dist/arbs.d.ts +1 -1
  181. package/dist/arbs.d.ts.map +1 -1
  182. package/dist/arbs.js +5 -3
  183. package/dist/errorReporter.d.ts +4 -4
  184. package/dist/errorReporter.d.ts.map +1 -1
  185. package/dist/errorReporter.js +20 -25
  186. package/dist/errors.d.ts +1 -1
  187. package/dist/fileUtil.d.ts +1 -1
  188. package/dist/fileUtil.d.ts.map +1 -1
  189. package/dist/index.d.ts +1 -1
  190. package/dist/logger/jsonLogger.d.ts +1 -1
  191. package/dist/logger/logFmtLogger.d.ts +1 -1
  192. package/dist/logger/shared.d.ts +1 -1
  193. package/dist/logger/shared.js +2 -2
  194. package/dist/logger.d.ts +1 -1
  195. package/dist/logger.d.ts.map +1 -1
  196. package/dist/rateLimit.d.ts +9 -3
  197. package/dist/rateLimit.d.ts.map +1 -1
  198. package/dist/rateLimit.js +5 -11
  199. package/dist/test.d.ts +2 -2
  200. package/dist/test.d.ts.map +1 -1
  201. package/dist/test.js +1 -1
  202. package/dist/vitest.d.ts +1 -1
  203. package/examples/query.ts +39 -35
  204. package/package.json +41 -37
  205. package/src/CUPS.ts +9 -11
  206. package/src/Emailer/Sendgrid.ts +17 -14
  207. package/src/Emailer/service.ts +9 -3
  208. package/src/MainFiberSet.ts +5 -6
  209. package/src/Model/Repository/Registry.ts +33 -0
  210. package/src/Model/Repository/ext.ts +96 -10
  211. package/src/Model/Repository/internal/internal.ts +97 -88
  212. package/src/Model/Repository/makeRepo.ts +12 -10
  213. package/src/Model/Repository/service.ts +31 -22
  214. package/src/Model/Repository/validation.ts +4 -4
  215. package/src/Model/Repository.ts +1 -0
  216. package/src/Model/dsl.ts +3 -3
  217. package/src/Model/filter/types/path/eager.ts +1 -2
  218. package/src/Model/query/dsl.ts +18 -18
  219. package/src/Model/query/new-kid-interpreter.ts +2 -2
  220. package/src/Model.ts +1 -0
  221. package/src/QueueMaker/SQLQueue.ts +121 -151
  222. package/src/QueueMaker/memQueue.ts +82 -103
  223. package/src/QueueMaker/sbqueue.ts +56 -86
  224. package/src/RequestContext.ts +8 -10
  225. package/src/RequestFiberSet.ts +4 -4
  226. package/src/Store/ContextMapContainer.ts +41 -2
  227. package/src/Store/Cosmos/query.ts +16 -20
  228. package/src/Store/Cosmos.ts +452 -342
  229. package/src/Store/Disk.ts +52 -49
  230. package/src/Store/Memory.ts +54 -48
  231. package/src/Store/SQL/Pg.ts +318 -0
  232. package/src/Store/SQL/query.ts +409 -0
  233. package/src/Store/SQL.ts +668 -0
  234. package/src/Store/codeFilter.ts +1 -0
  235. package/src/Store/index.ts +17 -2
  236. package/src/Store/service.ts +32 -8
  237. package/src/Store/utils.ts +23 -22
  238. package/src/adapters/SQL/Model.ts +10 -4
  239. package/src/adapters/ServiceBus.ts +112 -116
  240. package/src/adapters/cosmos-client.ts +2 -2
  241. package/src/adapters/index.ts +7 -0
  242. package/src/adapters/memQueue.ts +2 -2
  243. package/src/adapters/mongo-client.ts +2 -2
  244. package/src/adapters/redis-client.ts +2 -2
  245. package/src/api/ContextProvider.ts +12 -13
  246. package/src/api/internal/RequestContextMiddleware.ts +1 -1
  247. package/src/api/internal/auth.ts +246 -44
  248. package/src/api/internal/events.ts +12 -8
  249. package/src/api/layerUtils.ts +8 -8
  250. package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
  251. package/src/api/routing/middleware/middleware.ts +53 -12
  252. package/src/api/routing/middleware.ts +0 -2
  253. package/src/api/routing.ts +173 -63
  254. package/src/api/setupRequest.ts +28 -8
  255. package/src/arbs.ts +4 -2
  256. package/src/errorReporter.ts +62 -74
  257. package/src/logger/shared.ts +1 -1
  258. package/src/rateLimit.ts +30 -22
  259. package/src/test.ts +1 -1
  260. package/test/auth.test.ts +101 -0
  261. package/test/contextProvider.test.ts +11 -11
  262. package/test/controller.test.ts +19 -17
  263. package/test/dist/auth.test.d.ts.map +1 -0
  264. package/test/dist/contextProvider.test.d.ts.map +1 -1
  265. package/test/dist/controller.test.d.ts.map +1 -1
  266. package/test/dist/date-query.test.d.ts.map +1 -0
  267. package/test/dist/fixtures.d.ts +26 -12
  268. package/test/dist/fixtures.d.ts.map +1 -1
  269. package/test/dist/fixtures.js +12 -10
  270. package/test/dist/query.test.d.ts.map +1 -1
  271. package/test/dist/rawQuery.test.d.ts.map +1 -1
  272. package/test/dist/repository-ext.test.d.ts.map +1 -0
  273. package/test/dist/requires.test.d.ts.map +1 -1
  274. package/test/dist/router-generator.test.d.ts.map +1 -0
  275. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  276. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  277. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  278. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  279. package/test/dist/sql-store.test.d.ts.map +1 -0
  280. package/test/fixtures.ts +11 -9
  281. package/test/query.test.ts +216 -34
  282. package/test/rawQuery.test.ts +23 -19
  283. package/test/repository-ext.test.ts +60 -0
  284. package/test/requires.test.ts +6 -6
  285. package/test/router-generator.test.ts +183 -0
  286. package/test/routing-interruptibility.test.ts +63 -0
  287. package/test/rpc-e2e-invalidation.test.ts +249 -0
  288. package/test/rpc-multi-middleware.test.ts +78 -9
  289. package/test/rpc-stream-fullstack.test.ts +325 -0
  290. package/test/sql-store.test.ts +1064 -0
  291. package/test/validateSample.test.ts +15 -12
  292. package/tsconfig.examples.json +1 -1
  293. package/tsconfig.json +0 -1
  294. package/tsconfig.json.bak +2 -2
  295. package/tsconfig.src.json +35 -35
  296. package/tsconfig.test.json +2 -2
  297. package/dist/Operations.d.ts +0 -55
  298. package/dist/Operations.d.ts.map +0 -1
  299. package/dist/Operations.js +0 -102
  300. package/dist/OperationsRepo.d.ts +0 -41
  301. package/dist/OperationsRepo.d.ts.map +0 -1
  302. package/dist/OperationsRepo.js +0 -14
  303. package/eslint.config.mjs +0 -24
  304. package/src/Operations.ts +0 -235
  305. package/src/OperationsRepo.ts +0 -16
@@ -3,17 +3,17 @@ import { reportNonInterruptedFailure } from "@effect-app/infra/QueueMaker/errors
3
3
  import { type QueueBase, QueueMeta } from "@effect-app/infra/QueueMaker/service"
4
4
  import { subMinutes } from "date-fns"
5
5
  import { Effect, Fiber, type NonEmptyReadonlyArray, Option, S, Tracer } from "effect-app"
6
- import type { NonEmptyString255 } from "effect-app/Schema"
6
+ import { type NonEmptyString255 } from "effect-app/Schema"
7
7
  import { pretty } from "effect-app/utils"
8
8
  import { SqlClient } from "effect/unstable/sql"
9
9
  import { SQLModel } from "../adapters/SQL.js"
10
10
  import { InfraLogger } from "../logger.js"
11
11
 
12
- export const QueueId = S.Number.pipe(S.brand("QueueId"))
12
+ export const QueueId = S.Finite.pipe(S.brand("QueueId"))
13
13
  export type QueueId = typeof QueueId.Type
14
14
 
15
15
  // TODO: let the model track and Auto Generate versionColumn on every update instead
16
- export function makeSQLQueue<
16
+ export const makeSQLQueue = Effect.fnUntraced(function*<
17
17
  Evt extends { id: S.StringId; _tag: string },
18
18
  DrainEvt extends { id: S.StringId; _tag: string },
19
19
  EvtE,
@@ -24,166 +24,136 @@ export function makeSQLQueue<
24
24
  schema: S.Codec<Evt, EvtE>,
25
25
  drainSchema: S.Codec<DrainEvt, DrainEvtE>
26
26
  ) {
27
- return Effect.gen(function*() {
28
- const base = {
29
- id: SQLModel.Generated(QueueId),
30
- meta: SQLModel.JsonFromString(QueueMeta),
31
- name: S.NonEmptyString255,
32
- createdAt: SQLModel.DateTimeInsert,
33
- updatedAt: SQLModel.DateTimeUpdate,
34
- // TODO: at+owner
35
- processingAt: SQLModel.FieldOption(S.Date),
36
- finishedAt: SQLModel.FieldOption(S.Date),
37
- etag: S.String // TODO: use a SQLModel thing that auto updates it?
38
- // TODO: record locking.. / optimistic locking
39
- // rowVersion: SQLModel.DateTimeFromNumberWithNow
40
- }
41
- class Queue extends SQLModel.Class<Queue>("Queue")({
42
- body: SQLModel.JsonFromString(schema),
43
- ...base
44
- }) {}
45
- class Drain extends SQLModel.Class<Drain>("Drain")({
46
- body: SQLModel.JsonFromString(drainSchema),
47
- ...base
48
- }) {}
49
- const sql = yield* SqlClient.SqlClient
27
+ const base = {
28
+ id: SQLModel.Generated(QueueId),
29
+ meta: SQLModel.JsonFromString(QueueMeta),
30
+ name: S.NonEmptyString255,
31
+ createdAt: SQLModel.DateTimeInsert,
32
+ updatedAt: SQLModel.DateTimeUpdate,
33
+ // TODO: at+owner
34
+ processingAt: SQLModel.FieldOption(S.Date),
35
+ finishedAt: SQLModel.FieldOption(S.Date),
36
+ etag: S.String // TODO: use a SQLModel thing that auto updates it?
37
+ // TODO: record locking.. / optimistic locking
38
+ // rowVersion: SQLModel.DateTimeFromNumberWithNow
39
+ }
40
+ class Queue extends SQLModel.Class<Queue>("Queue")({
41
+ body: SQLModel.JsonFromString(schema),
42
+ ...base
43
+ }) {}
44
+ class Drain extends SQLModel.Class<Drain>("Drain")({
45
+ body: SQLModel.JsonFromString(drainSchema),
46
+ ...base
47
+ }) {}
48
+ const sql = yield* SqlClient.SqlClient
50
49
 
51
- const queueRepo = yield* SQLModel.makeRepository(Queue, {
52
- tableName: "queue",
53
- spanPrefix: "QueueRepo",
54
- idColumn: "id",
55
- versionColumn: "etag"
56
- })
50
+ const queueRepo = yield* SQLModel.makeRepository(Queue, {
51
+ tableName: "queue",
52
+ spanPrefix: "QueueRepo",
53
+ idColumn: "id",
54
+ versionColumn: "etag"
55
+ })
57
56
 
58
- const drainRepo = yield* SQLModel.makeRepository(Drain, {
59
- tableName: "queue",
60
- spanPrefix: "DrainRepo",
61
- idColumn: "id",
62
- versionColumn: "etag"
63
- })
57
+ const drainRepo = yield* SQLModel.makeRepository(Drain, {
58
+ tableName: "queue",
59
+ spanPrefix: "DrainRepo",
60
+ idColumn: "id",
61
+ versionColumn: "etag"
62
+ })
64
63
 
65
- const decodeDrain = S.decodeEffect(Drain)
64
+ const decodeDrain = S.decodeEffectConcurrently(Drain)
66
65
 
67
- const drain = Effect
68
- .sync(() => subMinutes(new Date(), 15))
69
- .pipe(
70
- Effect
71
- .andThen((limit) =>
72
- sql<typeof Drain.Encoded>`SELECT *
66
+ const drain = Effect.gen(function*() {
67
+ const limit = subMinutes(new Date(), 15)
68
+ return yield* sql<typeof Drain.Encoded>`SELECT *
73
69
  FROM queue
74
70
  WHERE name = ${queueDrainName} AND finishedAt IS NULL AND (processingAt IS NULL OR processingAt < ${limit.getTime()})
75
71
  LIMIT 1`
76
- )
77
- )
72
+ })
78
73
 
79
- const q = {
80
- offer: Effect.fnUntraced(function*(body: Evt, meta: typeof QueueMeta.Type) {
81
- yield* queueRepo.insertVoid({
82
- body,
83
- meta,
84
- name: queueName,
85
- processingAt: Option.none(),
86
- finishedAt: Option.none(),
87
- etag: crypto.randomUUID()
88
- })
89
- }),
90
- take: Effect.gen(function*() {
91
- while (true) {
92
- const [first] = yield* drain.pipe(Effect.withTracerEnabled(false)) // disable sql tracer otherwise we spam it..
93
- if (first) {
94
- const dec = yield* decodeDrain(first)
95
- const { createdAt, updatedAt, ...rest } = dec
96
- return yield* drainRepo.update(
97
- { ...rest, processingAt: Option.some(new Date()) } // auto in lib , etag: crypto.randomUUID()
98
- )
99
- }
100
- if (first) return first
101
- yield* Effect.sleep(250)
74
+ const q = {
75
+ offer: Effect.fnUntraced(function*(body: Evt, meta: typeof QueueMeta.Type) {
76
+ yield* queueRepo.insertVoid(Queue.insert.make({
77
+ body,
78
+ meta,
79
+ name: queueName,
80
+ processingAt: Option.none(),
81
+ finishedAt: Option.none(),
82
+ etag: crypto.randomUUID()
83
+ }))
84
+ }),
85
+ take: Effect.gen(function*() {
86
+ while (true) {
87
+ const [first] = yield* drain.pipe(Effect.withTracerEnabled(false)) // disable sql tracer otherwise we spam it..
88
+ if (first) {
89
+ const dec = yield* decodeDrain(first)
90
+ const { createdAt, updatedAt, ...rest } = dec
91
+ return yield* drainRepo.update(
92
+ Drain.update.make({ ...rest, processingAt: Option.some(new Date()) }) // auto in lib , etag: crypto.randomUUID()
93
+ )
102
94
  }
103
- }),
104
- finish: ({ createdAt, updatedAt, ...q }: Drain) =>
105
- drainRepo.updateVoid({ ...q, finishedAt: Option.some(new Date()) }) // auto in lib , etag: crypto.randomUUID()
106
- }
107
- const queue = {
108
- publish: (...messages: NonEmptyReadonlyArray<Evt>) =>
109
- getRequestContext
95
+ if (first) return first
96
+ yield* Effect.sleep(250)
97
+ }
98
+ }),
99
+ finish: Effect.fn(function*({ createdAt, updatedAt, ...q }: Drain) {
100
+ return yield* drainRepo.updateVoid(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) })) // auto in lib , etag: crypto.randomUUID()
101
+ })
102
+ }
103
+ const queue = {
104
+ publish: Effect.fn("queue.publish: " + queueName, { kind: "producer" })(function*(
105
+ ...messages: NonEmptyReadonlyArray<Evt>
106
+ ) {
107
+ yield* Effect.annotateCurrentSpan({ "message_tags": messages.map((_) => _._tag) })
108
+ const requestContext = yield* getRequestContext
109
+ yield* Effect.forEach(messages, (m) => q.offer(m, requestContext), { discard: true })
110
+ }),
111
+ drain: <DrainE, DrainR>(
112
+ handleEvent: (ks: DrainEvt) => Effect.Effect<void, DrainE, DrainR>,
113
+ sessionId?: string
114
+ ) => {
115
+ const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName })
116
+ const processMessage = Effect.fnUntraced(function*({ body, meta }: Drain) {
117
+ let effect = InfraLogger
118
+ .logDebug(`[${queueDrainName}] Processing incoming message`)
110
119
  .pipe(
111
- Effect.flatMap((requestContext) =>
112
- Effect
113
- .forEach(
114
- messages,
115
- (m) => q.offer(m, requestContext),
116
- {
117
- discard: true
120
+ Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
121
+ Effect.andThen(handleEvent(body)),
122
+ silenceAndReportError,
123
+ (_) =>
124
+ setupRequestContextWithCustomSpan(
125
+ _,
126
+ meta,
127
+ `queue.drain: ${queueDrainName}.${body._tag}`,
128
+ {
129
+ captureStackTrace: false,
130
+ kind: "consumer",
131
+ attributes: {
132
+ "queue.name": queueDrainName,
133
+ "queue.sessionId": sessionId,
134
+ "queue.input": body
118
135
  }
119
- )
120
- ),
121
- Effect.withSpan("queue.publish: " + queueName, {
122
- kind: "producer",
123
- attributes: { "message_tags": messages.map((_) => _._tag) }
124
- }, { captureStackTrace: false })
125
- ),
126
- drain: <DrainE, DrainR>(
127
- handleEvent: (ks: DrainEvt) => Effect.Effect<void, DrainE, DrainR>,
128
- sessionId?: string
129
- ) => {
130
- const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName })
131
- const processMessage = (msg: Drain) =>
132
- Effect
133
- .succeed(msg)
134
- .pipe(Effect
135
- .flatMap(({ body, meta }) => {
136
- let effect = InfraLogger
137
- .logDebug(`[${queueDrainName}] Processing incoming message`)
138
- .pipe(
139
- Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
140
- Effect.andThen(handleEvent(body)),
141
- silenceAndReportError,
142
- (_) =>
143
- setupRequestContextWithCustomSpan(
144
- _,
145
- meta,
146
- `queue.drain: ${queueDrainName}.${body._tag}`,
147
- {
148
- captureStackTrace: false,
149
- kind: "consumer",
150
- attributes: {
151
- "queue.name": queueDrainName,
152
- "queue.sessionId": sessionId,
153
- "queue.input": body
154
- }
155
- }
156
- )
157
- )
158
- if (meta.span) {
159
- effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
160
136
  }
161
- return effect
162
- }))
163
-
164
- return q
165
- .take
166
- .pipe(
167
- Effect.flatMap((x) =>
168
- processMessage(x).pipe(
169
- Effect.uninterruptible,
170
- Effect.forkChild,
171
- Effect.flatMap(Fiber.join),
172
- Effect.tap(q.finish(x))
173
137
  )
174
- ),
175
- silenceAndReportError,
176
- Effect.withSpan(`queue.drain: ${queueDrainName}`, {
177
- attributes: {
178
- "queue.type": "sql",
179
- "queue.name": queueDrainName,
180
- "queue.sessionId": sessionId
181
- }
182
- }),
183
- Effect.forever
184
138
  )
185
- }
139
+ if (meta.span) {
140
+ effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
141
+ }
142
+ return yield* effect
143
+ })
144
+
145
+ return Effect.fn(`queue.drain: ${queueDrainName}`, {
146
+ attributes: { "queue.type": "sql", "queue.name": queueDrainName, "queue.sessionId": sessionId }
147
+ })(function*() {
148
+ const x = yield* q.take
149
+ yield* processMessage(x).pipe(
150
+ Effect.uninterruptible,
151
+ Effect.forkChild,
152
+ Effect.flatMap(Fiber.join),
153
+ Effect.tap(q.finish(x))
154
+ )
155
+ }, (effect) => effect.pipe(silenceAndReportError, Effect.forever))()
186
156
  }
187
- return queue as QueueBase<Evt, DrainEvt>
188
- })
189
- }
157
+ }
158
+ return queue as QueueBase<Evt, DrainEvt>
159
+ })
@@ -6,9 +6,9 @@ import { MemQueue } from "../adapters/memQueue.js"
6
6
  import { getRequestContext, setupRequestContextWithCustomSpan } from "../api/setupRequest.js"
7
7
  import { InfraLogger } from "../logger.js"
8
8
  import { reportNonInterruptedFailure, reportNonInterruptedFailureCause } from "./errors.js"
9
- import { type QueueBase, QueueMeta } from "./service.js"
9
+ import { QueueMeta } from "./service.js"
10
10
 
11
- export function makeMemQueue<
11
+ export const makeMemQueue = Effect.fnUntraced(function*<
12
12
  Evt extends { id: S.StringId; _tag: string },
13
13
  DrainEvt extends { id: S.StringId; _tag: string },
14
14
  EvtE,
@@ -19,112 +19,91 @@ export function makeMemQueue<
19
19
  schema: S.Codec<Evt, EvtE>,
20
20
  drainSchema: S.Codec<DrainEvt, DrainEvtE>
21
21
  ) {
22
- return Effect.gen(function*() {
23
- const mem = yield* MemQueue
24
- const q = yield* mem.getOrCreateQueue(queueName)
25
- const qDrain = yield* mem.getOrCreateQueue(queueDrainName)
22
+ const mem = yield* MemQueue
23
+ const q = yield* mem.getOrCreateQueue(queueName)
24
+ const qDrain = yield* mem.getOrCreateQueue(queueDrainName)
26
25
 
27
- const wireSchema = S.Struct({ body: schema, meta: QueueMeta })
28
- const wireSchemaJson = S.fromJsonString(wireSchema)
29
- const encodePublish = S.encodeEffect(wireSchemaJson)
30
- const drainW = S.Struct({ body: drainSchema, meta: QueueMeta })
31
- const drainWJson = S.fromJsonString(drainW)
26
+ const wireSchema = S.Struct({ body: schema, meta: QueueMeta })
27
+ const wireSchemaJson = S.fromJsonString(S.toCodecJson(wireSchema))
28
+ const encodePublish = S.encodeEffect(wireSchemaJson)
29
+ const drainW = S.Struct({ body: drainSchema, meta: QueueMeta })
30
+ const drainWJson = S.fromJsonString(S.toCodecJson(drainW))
32
31
 
33
- const parseDrain = flow(S.decodeUnknownEffect(drainWJson), Effect.orDie)
32
+ const parseDrain = flow(S.decodeUnknownEffectConcurrently(drainWJson), Effect.orDie)
34
33
 
35
- const queue = {
36
- publish: (...messages: NonEmptyReadonlyArray<Evt>) =>
37
- getRequestContext
38
- .pipe(
39
- Effect.flatMap((requestContext) =>
40
- Effect
41
- .forEach(messages, (m) =>
42
- // we JSON encode, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
43
- encodePublish({ body: m, meta: requestContext }).pipe(
44
- Effect.orDie,
45
- // .tap((msg) => info("Publishing Mem Message: " + utils.inspect(msg)))
46
- Effect.flatMap((_) => Q.offer(q, _))
47
- ), { discard: true })
48
- ),
49
- Effect.withSpan("queue.publish: " + queueName, {
50
- kind: "producer",
51
- attributes: { "message_tags": messages.map((_) => _._tag) }
52
- }, { captureStackTrace: false })
53
- ),
54
- drain: <DrainE, DrainR>(
55
- handleEvent: (ks: DrainEvt) => Effect.Effect<void, DrainE, DrainR>,
56
- sessionId?: string
57
- ) => {
58
- const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName })
59
- const reportError = reportNonInterruptedFailureCause({ name: "MemQueue.drain." + queueDrainName })
60
- const processMessage = (msg: string) =>
61
- // we JSON parse, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
62
- parseDrain(msg).pipe(
34
+ const queue = {
35
+ publish: Effect.fn("queue.publish: " + queueName, { kind: "producer" })(function*(
36
+ ...messages: NonEmptyReadonlyArray<Evt>
37
+ ) {
38
+ yield* Effect.annotateCurrentSpan({ "message_tags": messages.map((_) => _._tag) })
39
+ const requestContext = yield* getRequestContext
40
+ // we JSON encode, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
41
+ yield* Effect.forEach(
42
+ messages,
43
+ (m) =>
44
+ encodePublish({ body: m, meta: requestContext }).pipe(
63
45
  Effect.orDie,
64
- Effect
65
- .flatMap(({ body, meta }) => {
66
- let effect = InfraLogger
67
- .logDebug(`[${queueDrainName}] Processing incoming message`)
68
- .pipe(
69
- Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
70
- Effect.andThen(handleEvent(body)),
71
- silenceAndReportError,
72
- (_) =>
73
- setupRequestContextWithCustomSpan(
74
- _,
75
- meta,
76
- `queue.drain: ${queueDrainName}.${body._tag}`,
77
- {
78
- captureStackTrace: false,
79
- kind: "consumer",
80
- attributes: {
81
- "queue.name": queueDrainName,
82
- "queue.sessionId": sessionId,
83
- "queue.input": body
84
- }
85
- }
86
- )
87
- )
88
- if (meta.span) {
89
- effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
90
- }
91
- return effect
92
- })
93
- )
94
- return Q
95
- .take(qDrain)
46
+ Effect.flatMap((_) => Q.offer(q, _))
47
+ ),
48
+ { discard: true }
49
+ )
50
+ }),
51
+ drain: <DrainE, DrainR>(
52
+ handleEvent: (ks: DrainEvt) => Effect.Effect<void, DrainE, DrainR>,
53
+ sessionId?: string
54
+ ) => {
55
+ const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName })
56
+ const reportError = reportNonInterruptedFailureCause({ name: "MemQueue.drain." + queueDrainName })
57
+ const processMessage = Effect.fnUntraced(function*(msg: string) {
58
+ // we JSON parse, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
59
+ const { body, meta } = yield* parseDrain(msg).pipe(Effect.orDie)
60
+ let effect = InfraLogger
61
+ .logDebug(`[${queueDrainName}] Processing incoming message`)
96
62
  .pipe(
97
- Effect
98
- .flatMap((x) =>
99
- processMessage(x).pipe(
100
- Effect.uninterruptible,
101
- Effect.forkChild,
102
- Effect.flatMap(Fiber.join),
103
- // normally a failed item would be returned to the queue and retried up to X times.
104
- Effect.flatMap((_) =>
105
- _._tag === "Failure" && !Cause.hasInterruptsOnly(_.cause)
106
- ? Q.offer(qDrain, x).pipe(
107
- // TODO: retry count tracking and max retries.
108
- Effect.delay("5 seconds"),
109
- Effect.tapCause(reportError),
110
- Effect.forkDetach
111
- )
112
- : Effect.void
113
- )
114
- )
115
- ),
63
+ Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
64
+ Effect.andThen(handleEvent(body)),
116
65
  silenceAndReportError,
117
- Effect.withSpan(`queue.drain: ${queueDrainName}`, {
118
- attributes: {
119
- "queue.type": "mem",
120
- "queue.name": queueDrainName,
121
- "queue.sessionId": sessionId
122
- }
123
- }),
124
- Effect.forever
66
+ (_) =>
67
+ setupRequestContextWithCustomSpan(
68
+ _,
69
+ meta,
70
+ `queue.drain: ${queueDrainName}.${body._tag}`,
71
+ {
72
+ captureStackTrace: false,
73
+ kind: "consumer",
74
+ attributes: {
75
+ "queue.name": queueDrainName,
76
+ "queue.sessionId": sessionId,
77
+ "queue.input": body
78
+ }
79
+ }
80
+ )
81
+ )
82
+ if (meta.span) {
83
+ effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
84
+ }
85
+ return yield* effect
86
+ })
87
+ return Effect.fn(`queue.drain: ${queueDrainName}`, {
88
+ attributes: { "queue.type": "mem", "queue.name": queueDrainName, "queue.sessionId": sessionId }
89
+ })(function*() {
90
+ const x = yield* Q.take(qDrain)
91
+ const exit = yield* processMessage(x).pipe(
92
+ Effect.uninterruptible,
93
+ Effect.forkChild,
94
+ Effect.flatMap(Fiber.join)
95
+ )
96
+ if (exit._tag === "Failure" && !Cause.hasInterruptsOnly(exit.cause)) {
97
+ // normally a failed item would be returned to the queue and retried up to X times.
98
+ yield* Q.offer(qDrain, x).pipe(
99
+ // TODO: retry count tracking and max retries.
100
+ Effect.delay("5 seconds"),
101
+ Effect.tapCause(reportError),
102
+ Effect.forkDetach
125
103
  )
126
- }
104
+ }
105
+ }, (effect) => effect.pipe(silenceAndReportError, Effect.forever))()
127
106
  }
128
- return queue as QueueBase<Evt, DrainEvt>
129
- })
130
- }
107
+ }
108
+ return queue
109
+ })