@wtfalch/reporting 0.1.0 → 0.1.1
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/writer.d.ts +9 -2
- package/dist/writer.js +27 -11
- package/package.json +1 -1
package/dist/writer.d.ts
CHANGED
|
@@ -27,11 +27,18 @@ export declare class Writer {
|
|
|
27
27
|
private enqueue;
|
|
28
28
|
/** Once per idle period through `defer`, and always on the timer. */
|
|
29
29
|
private schedule;
|
|
30
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Drain until the queue is empty and nothing is in flight, or the deadline.
|
|
32
|
+
* Two callers overlap all the time (the timer and a request's `after()`,
|
|
33
|
+
* the tick and its own timer), so "empty" is not enough: a row another
|
|
34
|
+
* flush spliced off the queue a moment ago is still on its way, and a
|
|
35
|
+
* caller that returned on an empty queue would read the table too early.
|
|
36
|
+
* Every caller therefore waits for whatever is in flight and looks again.
|
|
37
|
+
*/
|
|
31
38
|
flush(opts?: {
|
|
32
39
|
deadlineMs?: number;
|
|
33
40
|
}): Promise<void>;
|
|
34
|
-
|
|
41
|
+
/** One insert of one batch. Resolves true on success; never throws. */
|
|
35
42
|
private flushOnce;
|
|
36
43
|
stats(): Stats;
|
|
37
44
|
}
|
package/dist/writer.js
CHANGED
|
@@ -95,25 +95,41 @@ export class Writer {
|
|
|
95
95
|
this.timer.unref?.();
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* Drain until the queue is empty and nothing is in flight, or the deadline.
|
|
100
|
+
* Two callers overlap all the time (the timer and a request's `after()`,
|
|
101
|
+
* the tick and its own timer), so "empty" is not enough: a row another
|
|
102
|
+
* flush spliced off the queue a moment ago is still on its way, and a
|
|
103
|
+
* caller that returned on an empty queue would read the table too early.
|
|
104
|
+
* Every caller therefore waits for whatever is in flight and looks again.
|
|
105
|
+
*/
|
|
99
106
|
async flush(opts = {}) {
|
|
100
107
|
const deadline = Date.now() + (opts.deadlineMs ?? 5000);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
while (this.queue.length > 0 && Date.now() < deadline) {
|
|
104
|
-
this.inFlight = this.flushOnce();
|
|
105
|
-
try {
|
|
108
|
+
while (Date.now() < deadline) {
|
|
109
|
+
if (this.inFlight) {
|
|
106
110
|
await this.inFlight;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (this.queue.length === 0)
|
|
114
|
+
break;
|
|
115
|
+
const attempt = this.flushOnce();
|
|
116
|
+
this.inFlight = attempt;
|
|
117
|
+
let ok = false;
|
|
118
|
+
try {
|
|
119
|
+
ok = await attempt;
|
|
107
120
|
}
|
|
108
121
|
finally {
|
|
109
|
-
this.inFlight
|
|
122
|
+
if (this.inFlight === attempt)
|
|
123
|
+
this.inFlight = null;
|
|
110
124
|
}
|
|
111
|
-
|
|
125
|
+
// A failed insert leaves its rows queued; do not spin on the database
|
|
126
|
+
// inside one call. The timer and the next defer try again.
|
|
127
|
+
if (!ok)
|
|
112
128
|
break;
|
|
113
129
|
}
|
|
114
130
|
this.deferred = false;
|
|
115
131
|
}
|
|
116
|
-
|
|
132
|
+
/** One insert of one batch. Resolves true on success; never throws. */
|
|
117
133
|
async flushOnce() {
|
|
118
134
|
const batch = this.queue.splice(0, this.o.batchSize);
|
|
119
135
|
if (this.droppedSinceReport > 0) {
|
|
@@ -133,11 +149,10 @@ export class Writer {
|
|
|
133
149
|
try {
|
|
134
150
|
await this.o.db.insert(reportingEvents).values(batch);
|
|
135
151
|
this.flushed += batch.length;
|
|
136
|
-
|
|
152
|
+
return true;
|
|
137
153
|
}
|
|
138
154
|
catch (error) {
|
|
139
155
|
this.failedFlushes += 1;
|
|
140
|
-
this.lastFailed = true;
|
|
141
156
|
// Back at the front, so order survives; the bound still applies, and
|
|
142
157
|
// whatever does not fit is counted as dropped rather than kept for ever.
|
|
143
158
|
const room = Math.max(0, this.o.queueLimit - this.queue.length);
|
|
@@ -146,6 +161,7 @@ export class Writer {
|
|
|
146
161
|
this.droppedSinceReport += batch.length - kept.length;
|
|
147
162
|
this.queue.unshift(...kept);
|
|
148
163
|
this.o.log.error({ err: describe(error), rows: batch.length, queued: this.queue.length }, 'reporting: flush failed; rows stay queued');
|
|
164
|
+
return false;
|
|
149
165
|
}
|
|
150
166
|
}
|
|
151
167
|
stats() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/reporting",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The estate's operational event log and housekeeping tick: a writer that never fails a request, a claim protocol that needs no scheduler, and the readers an operator opens. Per-app Postgres, host-supplied logger, framework-neutral core with a Next entry.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|