@c4t4/heyamigo 0.9.8 → 0.9.10
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/boot.js +4 -1
- package/dist/cli/setup.js +4 -1
- package/dist/db/schema.js +31 -0
- package/dist/queue/async-tasks.js +61 -61
- package/dist/queue/memory-worker.js +169 -0
- package/dist/queue/memory-writes.js +136 -0
- package/dist/queue/orchestrator.js +5 -0
- package/dist/queue/worker.js +35 -32
- package/migrations/0005_phase5_memory_writes.sql +17 -0
- package/migrations/meta/0005_snapshot.json +777 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/dist/queue/persistence.js +0 -68
- package/dist/queue/queue.js +0 -49
package/package.json
CHANGED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'fs';
|
|
2
|
-
import { resolve } from 'path';
|
|
3
|
-
import { logger } from '../logger.js';
|
|
4
|
-
const QUEUE_DIR = resolve(process.cwd(), 'storage/queue');
|
|
5
|
-
const PENDING_FILE = resolve(QUEUE_DIR, 'pending.jsonl');
|
|
6
|
-
function ensureDir() {
|
|
7
|
-
mkdirSync(QUEUE_DIR, { recursive: true });
|
|
8
|
-
}
|
|
9
|
-
export function persistJob(job) {
|
|
10
|
-
ensureDir();
|
|
11
|
-
const line = JSON.stringify({ ...job, enqueuedAt: Date.now() }) + '\n';
|
|
12
|
-
writeFileSync(PENDING_FILE, line, { flag: 'a', encoding: 'utf-8' });
|
|
13
|
-
}
|
|
14
|
-
export function removeJob(job) {
|
|
15
|
-
if (!existsSync(PENDING_FILE))
|
|
16
|
-
return;
|
|
17
|
-
try {
|
|
18
|
-
const lines = readFileSync(PENDING_FILE, 'utf-8')
|
|
19
|
-
.split('\n')
|
|
20
|
-
.filter(Boolean);
|
|
21
|
-
const remaining = lines.filter((line) => {
|
|
22
|
-
try {
|
|
23
|
-
const parsed = JSON.parse(line);
|
|
24
|
-
return !(parsed.jid === job.jid && parsed.text === job.text);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
if (remaining.length === 0) {
|
|
31
|
-
unlinkSync(PENDING_FILE);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
writeFileSync(PENDING_FILE, remaining.join('\n') + '\n', 'utf-8');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
// best-effort cleanup
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export function loadPendingJobs() {
|
|
42
|
-
if (!existsSync(PENDING_FILE))
|
|
43
|
-
return [];
|
|
44
|
-
try {
|
|
45
|
-
const lines = readFileSync(PENDING_FILE, 'utf-8')
|
|
46
|
-
.split('\n')
|
|
47
|
-
.filter(Boolean);
|
|
48
|
-
const jobs = [];
|
|
49
|
-
for (const line of lines) {
|
|
50
|
-
try {
|
|
51
|
-
const parsed = JSON.parse(line);
|
|
52
|
-
jobs.push(parsed);
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
logger.warn({ line: line.slice(0, 100) }, 'skipping malformed pending job');
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
logger.info({ count: jobs.length }, 'loaded pending jobs from disk');
|
|
59
|
-
return jobs;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
export function clearPending() {
|
|
66
|
-
if (existsSync(PENDING_FILE))
|
|
67
|
-
unlinkSync(PENDING_FILE);
|
|
68
|
-
}
|
package/dist/queue/queue.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import fastq from 'fastq';
|
|
2
|
-
import { logger } from '../logger.js';
|
|
3
|
-
import { loadPendingJobs, persistJob, removeJob } from './persistence.js';
|
|
4
|
-
import { processJob } from './worker.js';
|
|
5
|
-
const queues = new Map();
|
|
6
|
-
function getQueue(jid) {
|
|
7
|
-
let q = queues.get(jid);
|
|
8
|
-
if (!q) {
|
|
9
|
-
q = fastq.promise(async (job) => {
|
|
10
|
-
try {
|
|
11
|
-
const result = await processJob(job);
|
|
12
|
-
removeJob(job);
|
|
13
|
-
return result;
|
|
14
|
-
}
|
|
15
|
-
catch (err) {
|
|
16
|
-
removeJob(job);
|
|
17
|
-
throw err;
|
|
18
|
-
}
|
|
19
|
-
}, 1);
|
|
20
|
-
queues.set(jid, q);
|
|
21
|
-
}
|
|
22
|
-
return q;
|
|
23
|
-
}
|
|
24
|
-
export async function enqueue(job) {
|
|
25
|
-
persistJob(job);
|
|
26
|
-
return getQueue(job.jid).push(job);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* On boot, replay any jobs that were persisted but never completed
|
|
30
|
-
* (process crashed mid-queue). Returns a promise that resolves when
|
|
31
|
-
* all replayed jobs finish or fail. Caller provides a handler for
|
|
32
|
-
* results since the original WAMessage context is gone.
|
|
33
|
-
*/
|
|
34
|
-
export async function replayPending(onResult) {
|
|
35
|
-
const pending = loadPendingJobs();
|
|
36
|
-
if (!pending.length)
|
|
37
|
-
return;
|
|
38
|
-
logger.info({ count: pending.length }, 'replaying pending jobs from last session');
|
|
39
|
-
const promises = pending.map(async (job) => {
|
|
40
|
-
try {
|
|
41
|
-
const result = await getQueue(job.jid).push(job);
|
|
42
|
-
await onResult(job, result);
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
logger.error({ err, jid: job.jid }, 'replayed job failed');
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
await Promise.allSettled(promises);
|
|
49
|
-
}
|