s3db.js 11.2.0 → 11.2.2
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/s3db-cli.js +55029 -0
- package/dist/s3db.cjs.js +52 -5
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +52 -5
- package/dist/s3db.es.js.map +1 -1
- package/package.json +1 -4
- package/src/plugins/eventual-consistency/config.js +4 -1
- package/src/plugins/eventual-consistency/consolidation.js +38 -4
- package/src/plugins/eventual-consistency/install.js +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "s3db.js",
|
|
3
|
-
"version": "11.2.
|
|
3
|
+
"version": "11.2.2",
|
|
4
4
|
"description": "Use AWS S3, the world's most reliable document storage, as a database with this ORM.",
|
|
5
5
|
"main": "dist/s3db.cjs.js",
|
|
6
6
|
"module": "dist/s3db.es.js",
|
|
@@ -142,10 +142,7 @@
|
|
|
142
142
|
"test:full": "pnpm run test:js && pnpm run test:ts",
|
|
143
143
|
"benchmark": "node benchmark-compression.js",
|
|
144
144
|
"benchmark:partitions": "node docs/benchmarks/partitions-matrix.js",
|
|
145
|
-
"version": "echo 'Use pnpm run release v<version> instead of npm version'",
|
|
146
145
|
"release:check": "./scripts/pre-release-check.sh",
|
|
147
|
-
"release:prepare": "pnpm run build:binaries && echo 'Binaries ready for GitHub release'",
|
|
148
|
-
"release": "./scripts/release.sh",
|
|
149
146
|
"validate:types": "pnpm run test:ts && echo 'TypeScript definitions are valid!'",
|
|
150
147
|
"test:ts:runtime": "tsx tests/typescript/types-runtime-simple.ts"
|
|
151
148
|
}
|
|
@@ -47,9 +47,12 @@ export function createConfig(options, detectedTimezone) {
|
|
|
47
47
|
autoConsolidate: consolidation.auto !== false,
|
|
48
48
|
mode: consolidation.mode || 'async',
|
|
49
49
|
|
|
50
|
-
// ✅
|
|
50
|
+
// ✅ Performance tuning - Mark applied concurrency (default 50, up from 10)
|
|
51
51
|
markAppliedConcurrency: consolidation.markAppliedConcurrency ?? 50,
|
|
52
52
|
|
|
53
|
+
// ✅ Performance tuning - Recalculate concurrency (default 50, up from 10)
|
|
54
|
+
recalculateConcurrency: consolidation.recalculateConcurrency ?? 50,
|
|
55
|
+
|
|
53
56
|
// Late arrivals
|
|
54
57
|
lateArrivalStrategy: lateArrivals.strategy || 'warn',
|
|
55
58
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import tryFn from "../../concerns/try-fn.js";
|
|
7
7
|
import { PromisePool } from "@supercharge/promise-pool";
|
|
8
8
|
import { idGenerator } from "../../concerns/id.js";
|
|
9
|
-
import { getCohortInfo, createSyntheticSetTransaction } from "./utils.js";
|
|
9
|
+
import { getCohortInfo, createSyntheticSetTransaction, ensureCohortHour } from "./utils.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Start consolidation timer for a handler
|
|
@@ -612,12 +612,43 @@ export async function consolidateRecord(
|
|
|
612
612
|
.for(transactionsToUpdate)
|
|
613
613
|
.withConcurrency(markAppliedConcurrency) // ✅ Configurável e maior!
|
|
614
614
|
.process(async (txn) => {
|
|
615
|
+
// ✅ FIX BUG #3: Ensure cohort fields exist before marking as applied
|
|
616
|
+
// This handles legacy transactions missing cohortHour, cohortDate, etc.
|
|
617
|
+
const txnWithCohorts = ensureCohortHour(txn, config.cohort.timezone, false);
|
|
618
|
+
|
|
619
|
+
// Build update data with applied flag
|
|
620
|
+
const updateData = { applied: true };
|
|
621
|
+
|
|
622
|
+
// Add missing cohort fields if they were calculated
|
|
623
|
+
if (txnWithCohorts.cohortHour && !txn.cohortHour) {
|
|
624
|
+
updateData.cohortHour = txnWithCohorts.cohortHour;
|
|
625
|
+
}
|
|
626
|
+
if (txnWithCohorts.cohortDate && !txn.cohortDate) {
|
|
627
|
+
updateData.cohortDate = txnWithCohorts.cohortDate;
|
|
628
|
+
}
|
|
629
|
+
if (txnWithCohorts.cohortWeek && !txn.cohortWeek) {
|
|
630
|
+
updateData.cohortWeek = txnWithCohorts.cohortWeek;
|
|
631
|
+
}
|
|
632
|
+
if (txnWithCohorts.cohortMonth && !txn.cohortMonth) {
|
|
633
|
+
updateData.cohortMonth = txnWithCohorts.cohortMonth;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Handle null value field (legacy data might have null)
|
|
637
|
+
if (txn.value === null || txn.value === undefined) {
|
|
638
|
+
updateData.value = 1; // Default to 1 for backward compatibility
|
|
639
|
+
}
|
|
640
|
+
|
|
615
641
|
const [ok, err] = await tryFn(() =>
|
|
616
|
-
transactionResource.update(txn.id,
|
|
642
|
+
transactionResource.update(txn.id, updateData)
|
|
617
643
|
);
|
|
618
644
|
|
|
619
645
|
if (!ok && config.verbose) {
|
|
620
|
-
console.warn(
|
|
646
|
+
console.warn(
|
|
647
|
+
`[EventualConsistency] Failed to mark transaction ${txn.id} as applied:`,
|
|
648
|
+
err?.message,
|
|
649
|
+
'Update data:',
|
|
650
|
+
updateData
|
|
651
|
+
);
|
|
621
652
|
}
|
|
622
653
|
|
|
623
654
|
return ok;
|
|
@@ -917,9 +948,12 @@ export async function recalculateRecord(
|
|
|
917
948
|
// Exclude anchor transactions (they should always be applied)
|
|
918
949
|
const transactionsToReset = allTransactions.filter(txn => txn.source !== 'anchor');
|
|
919
950
|
|
|
951
|
+
// ✅ OPTIMIZATION: Use higher concurrency for recalculate (default 50 vs 10)
|
|
952
|
+
const recalculateConcurrency = config.recalculateConcurrency || 50;
|
|
953
|
+
|
|
920
954
|
const { results, errors } = await PromisePool
|
|
921
955
|
.for(transactionsToReset)
|
|
922
|
-
.withConcurrency(
|
|
956
|
+
.withConcurrency(recalculateConcurrency)
|
|
923
957
|
.process(async (txn) => {
|
|
924
958
|
const [ok, err] = await tryFn(() =>
|
|
925
959
|
transactionResource.update(txn.id, { applied: false })
|
|
@@ -173,6 +173,28 @@ async function createAnalyticsResource(handler, database, resourceName, fieldNam
|
|
|
173
173
|
},
|
|
174
174
|
behavior: 'body-overflow',
|
|
175
175
|
timestamps: false,
|
|
176
|
+
asyncPartitions: true,
|
|
177
|
+
// ✅ Multi-attribute partitions for optimal analytics query performance
|
|
178
|
+
partitions: {
|
|
179
|
+
// Query by period (hour/day/week/month)
|
|
180
|
+
byPeriod: {
|
|
181
|
+
fields: { period: 'string' }
|
|
182
|
+
},
|
|
183
|
+
// Query by period + cohort (e.g., all hour records for specific hours)
|
|
184
|
+
byPeriodCohort: {
|
|
185
|
+
fields: {
|
|
186
|
+
period: 'string',
|
|
187
|
+
cohort: 'string'
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
// Query by field + period (e.g., all daily analytics for clicks field)
|
|
191
|
+
byFieldPeriod: {
|
|
192
|
+
fields: {
|
|
193
|
+
field: 'string',
|
|
194
|
+
period: 'string'
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
176
198
|
createdBy: 'EventualConsistencyPlugin'
|
|
177
199
|
})
|
|
178
200
|
);
|