@remit/search-index-worker 0.0.14 → 0.0.16
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/package.json +1 -1
- package/src/consumer.ts +3 -4
- package/src/data-ports.ts +4 -5
- package/src/handler.ts +2 -3
- package/src/services.ts +0 -2
- package/src/reindex.ts +0 -63
- package/src/run-reindex.ts +0 -22
package/package.json
CHANGED
package/src/consumer.ts
CHANGED
|
@@ -50,10 +50,9 @@ export interface SqsConsumerConfig {
|
|
|
50
50
|
* via `processBatch` (a batch of one) — the same per-message logic the AWS
|
|
51
51
|
* Lambda handler runs, reused so the two deployment shapes (Lambda event
|
|
52
52
|
* source mapping vs. a long-running container/pm2 process) share one
|
|
53
|
-
* indexing implementation. Used by the
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* see its `worker.ts`), it does not consume them.
|
|
53
|
+
* indexing implementation. Used by the self-host stack, where the search-index
|
|
54
|
+
* queue has no Lambda event source: the outbox drain relays committed events
|
|
55
|
+
* onto this queue (the producer side) and this consumer takes them off it.
|
|
57
56
|
*
|
|
58
57
|
* A message is deleted only when `processBatch` reports no failure for it;
|
|
59
58
|
* a failure leaves it on the queue so its visibility timeout lapses and SQS
|
package/src/data-ports.ts
CHANGED
|
@@ -17,11 +17,10 @@ export interface SearchIndexDataPorts {
|
|
|
17
17
|
* one — this hook is `undefined` there, and the handler uses the message's
|
|
18
18
|
* own `accountId` unchanged (see `prepareUpsert` in handler.ts).
|
|
19
19
|
*
|
|
20
|
-
* The
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* retried — see handler.ts).
|
|
20
|
+
* The outbox carries a plain `message_id`, so the relational drain has no
|
|
21
|
+
* accountId to attach; this hook derives it from the message's mailbox at
|
|
22
|
+
* consume time instead. Returns null when the mailbox can't be resolved (the
|
|
23
|
+
* message is skipped, not retried — see handler.ts).
|
|
25
24
|
*/
|
|
26
25
|
resolveAccountId?: (messageId: string) => Promise<string | null>;
|
|
27
26
|
}
|
package/src/handler.ts
CHANGED
|
@@ -86,9 +86,8 @@ const deleteMessage = async (
|
|
|
86
86
|
// upsert per message means a record S3 Vectors rejects (e.g. a metadata
|
|
87
87
|
// ValidationException) dead-letters on its own — its siblings in the
|
|
88
88
|
// batch still index instead of retrying forever behind a poison record.
|
|
89
|
-
// Exported so the long-running
|
|
90
|
-
//
|
|
91
|
-
// outside the Lambda batch shape, reusing this exact logic.
|
|
89
|
+
// Exported so the long-running consumer (`consumer.ts`) can process one
|
|
90
|
+
// message at a time outside the Lambda batch shape, reusing this exact logic.
|
|
92
91
|
export const upsertMessage = async (
|
|
93
92
|
message: Extract<ParsedQueueMessage, { kind: "upsert" }>,
|
|
94
93
|
services: Services,
|
package/src/services.ts
CHANGED
|
@@ -73,8 +73,6 @@ export const getServices = async (): Promise<Services> => {
|
|
|
73
73
|
return cached;
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
export const createServices = (overrides: Services): Services => overrides;
|
|
77
|
-
|
|
78
76
|
/** Reset the singleton — test use only. */
|
|
79
77
|
export const _resetForTest = (): void => {
|
|
80
78
|
cached = undefined;
|
package/src/reindex.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { Logger } from "@remit/logger-lambda";
|
|
2
|
-
import pMap from "p-map";
|
|
3
|
-
import type { Pool } from "pg";
|
|
4
|
-
import { type IndexOutcome, upsertMessage } from "./handler.js";
|
|
5
|
-
import type { Services } from "./services.js";
|
|
6
|
-
|
|
7
|
-
export interface ReindexResult {
|
|
8
|
-
total: number;
|
|
9
|
-
indexed: number;
|
|
10
|
-
skipped: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const NOT_APPLICABLE_ACCOUNT_ID = "reindex-all";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Re-embed every body-synced Postgres message. Concurrent (pMap) and
|
|
17
|
-
* force-upserting so a model change or a repair repopulates the whole store;
|
|
18
|
-
* keys-only scan keeps the hot path off `describe()`. Postgres-only — the
|
|
19
|
-
* `accountId` on the synthetic upsert message is a placeholder: `services`
|
|
20
|
-
* must carry `resolveAccountId` (true whenever `DATA_BACKEND=postgres`; see
|
|
21
|
-
* `data-ports.ts`), which derives the real one from each message's mailbox.
|
|
22
|
-
*/
|
|
23
|
-
export const reindexAll = async (
|
|
24
|
-
pool: Pool,
|
|
25
|
-
services: Services,
|
|
26
|
-
log: Logger,
|
|
27
|
-
options?: { concurrency?: number },
|
|
28
|
-
): Promise<ReindexResult> => {
|
|
29
|
-
const rows = await pool.query<{ message_id: string }>(
|
|
30
|
-
"SELECT message_id FROM message WHERE body_storage_key IS NOT NULL",
|
|
31
|
-
);
|
|
32
|
-
const messageIds = rows.rows.map((row) => row.message_id);
|
|
33
|
-
|
|
34
|
-
let indexed = 0;
|
|
35
|
-
let skipped = 0;
|
|
36
|
-
await pMap(
|
|
37
|
-
messageIds,
|
|
38
|
-
async (messageId) => {
|
|
39
|
-
let outcome: IndexOutcome | undefined;
|
|
40
|
-
const taskServices: Services = {
|
|
41
|
-
...services,
|
|
42
|
-
onIndexOutcome: (o) => {
|
|
43
|
-
outcome = o;
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
await upsertMessage(
|
|
47
|
-
{
|
|
48
|
-
kind: "upsert",
|
|
49
|
-
accountId: NOT_APPLICABLE_ACCOUNT_ID,
|
|
50
|
-
messageId,
|
|
51
|
-
force: true,
|
|
52
|
-
},
|
|
53
|
-
taskServices,
|
|
54
|
-
log,
|
|
55
|
-
);
|
|
56
|
-
if (outcome?.status === "indexed") indexed += 1;
|
|
57
|
-
else skipped += 1;
|
|
58
|
-
},
|
|
59
|
-
{ concurrency: options?.concurrency ?? 8 },
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
return { total: messageIds.length, indexed, skipped };
|
|
63
|
-
};
|
package/src/run-reindex.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "@remit/logger-lambda";
|
|
2
|
-
import pg from "pg";
|
|
3
|
-
import { reindexAll } from "./reindex.js";
|
|
4
|
-
import { getServices } from "./services.js";
|
|
5
|
-
|
|
6
|
-
const log = createLogger();
|
|
7
|
-
|
|
8
|
-
const main = async (): Promise<void> => {
|
|
9
|
-
const connectionString = process.env.PG_CONNECTION_URL;
|
|
10
|
-
if (!connectionString) throw new Error("PG_CONNECTION_URL is required");
|
|
11
|
-
|
|
12
|
-
const pool = new pg.Pool({ connectionString });
|
|
13
|
-
const services = await getServices();
|
|
14
|
-
|
|
15
|
-
const result = await reindexAll(pool, services, log);
|
|
16
|
-
log.info("reindex complete", { ...result });
|
|
17
|
-
|
|
18
|
-
await pool.end();
|
|
19
|
-
process.exit(0);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
await main();
|