musora-content-services 2.111.4 → 2.111.5
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/CHANGELOG.md +2 -0
- package/package.json +1 -1
- package/src/services/sync/context/providers/session.ts +6 -0
- package/src/services/sync/manager.ts +1 -1
- package/src/services/sync/repositories/base.ts +8 -8
- package/src/services/sync/retry.ts +6 -1
- package/src/services/sync/store/index.ts +8 -6
- package/src/services/sync/telemetry/sampling.ts +2 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [2.111.5](https://github.com/railroadmedia/musora-content-services/compare/v2.111.4...v2.111.5) (2026-01-07)
|
|
6
|
+
|
|
5
7
|
### [2.111.4](https://github.com/railroadmedia/musora-content-services/compare/v2.111.3...v2.111.4) (2026-01-07)
|
|
6
8
|
|
|
7
9
|
### [2.111.3](https://github.com/railroadmedia/musora-content-services/compare/v2.111.2...v2.111.3) (2026-01-06)
|
package/package.json
CHANGED
|
@@ -124,7 +124,7 @@ export default class SyncManager {
|
|
|
124
124
|
|
|
125
125
|
// can fail synchronously immediately (e.g., schema/migration validation errors)
|
|
126
126
|
// or asynchronously (e.g., indexedDB errors synchronously OR asynchronously (!))
|
|
127
|
-
const database = this.telemetry.trace({ name: 'db:init' }, this.initDatabase)
|
|
127
|
+
const database = this.telemetry.trace({ name: 'db:init', attributes: { ...this.context.session.toJSON() } }, this.initDatabase)
|
|
128
128
|
|
|
129
129
|
Object.entries(this.storeConfigsRegistry).forEach(([table, storeConfig]) => {
|
|
130
130
|
this.storesRegistry[table] = this.createStore(storeConfig, database)
|
|
@@ -77,56 +77,56 @@ export default class SyncRepository<TModel extends BaseModel> {
|
|
|
77
77
|
|
|
78
78
|
protected async insertOne(builder: (record: TModel) => void) {
|
|
79
79
|
return this.store.telemetry.trace(
|
|
80
|
-
{ name: `insertOne:${this.store.model.table}`, op: 'insert' },
|
|
80
|
+
{ name: `insertOne:${this.store.model.table}`, op: 'insert', attributes: { ...this.context.session.toJSON() } },
|
|
81
81
|
(span) => this._respondToWrite(() => this.store.insertOne(builder, span), span)
|
|
82
82
|
)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
protected async updateOneId(id: RecordId, builder: (record: TModel) => void) {
|
|
86
86
|
return this.store.telemetry.trace(
|
|
87
|
-
{ name: `updateOne:${this.store.model.table}`, op: 'update' },
|
|
87
|
+
{ name: `updateOne:${this.store.model.table}`, op: 'update', attributes: { ...this.context.session.toJSON() } },
|
|
88
88
|
(span) => this._respondToWrite(() => this.store.updateOneId(id, builder, span), span)
|
|
89
89
|
)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
protected async upsertOne(id: RecordId, builder: (record: TModel) => void, { skipPush = false } = {}) {
|
|
93
93
|
return this.store.telemetry.trace(
|
|
94
|
-
{ name: `upsertOne:${this.store.model.table}`, op: 'upsert' },
|
|
94
|
+
{ name: `upsertOne:${this.store.model.table}`, op: 'upsert', attributes: { ...this.context.session.toJSON() } },
|
|
95
95
|
(span) => this._respondToWrite(() => this.store.upsertOne(id, builder, span, {skipPush}), span)
|
|
96
96
|
)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
protected async upsertOneTentative(id: RecordId, builder: (record: TModel) => void) {
|
|
100
100
|
return this.store.telemetry.trace(
|
|
101
|
-
{ name: `upsertOneTentative:${this.store.model.table}`, op: 'upsert' },
|
|
101
|
+
{ name: `upsertOneTentative:${this.store.model.table}`, op: 'upsert', attributes: { ...this.context.session.toJSON() } },
|
|
102
102
|
(span) => this._respondToWrite(() => this.store.upsertOneTentative(id, builder, span), span)
|
|
103
103
|
)
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
protected async upsertSome(builders: Record<RecordId, (record: TModel) => void>, { skipPush = false } = {}) {
|
|
107
107
|
return this.store.telemetry.trace(
|
|
108
|
-
{ name: `upsertSome:${this.store.model.table}`, op: 'upsert' },
|
|
108
|
+
{ name: `upsertSome:${this.store.model.table}`, op: 'upsert', attributes: { ...this.context.session.toJSON() } },
|
|
109
109
|
(span) => this._respondToWrite(() => this.store.upsertSome(builders, span, {skipPush}), span)
|
|
110
110
|
)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
protected async upsertSomeTentative(builders: Record<RecordId, (record: TModel) => void>, { skipPush = false } = {}) {
|
|
114
114
|
return this.store.telemetry.trace(
|
|
115
|
-
{ name: `upsertSomeTentative:${this.store.model.table}`, op: 'upsert' },
|
|
115
|
+
{ name: `upsertSomeTentative:${this.store.model.table}`, op: 'upsert', attributes: { ...this.context.session.toJSON() } },
|
|
116
116
|
(span) => this._respondToWrite(() => this.store.upsertSomeTentative(builders, span, {skipPush}), span)
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
protected async deleteOne(id: RecordId, { skipPush = false } = {}) {
|
|
121
121
|
return this.store.telemetry.trace(
|
|
122
|
-
{ name: `delete:${this.store.model.table}`, op: 'delete' },
|
|
122
|
+
{ name: `delete:${this.store.model.table}`, op: 'delete', attributes: { ...this.context.session.toJSON() } },
|
|
123
123
|
(span) => this._respondToWriteIds(() => this.store.deleteOne(id, span, {skipPush}), span)
|
|
124
124
|
)
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
protected async deleteSome(ids: RecordId[]) {
|
|
128
128
|
return this.store.telemetry.trace(
|
|
129
|
-
{ name: `deleteSome:${this.store.model.table}`, op: 'delete' },
|
|
129
|
+
{ name: `deleteSome:${this.store.model.table}`, op: 'delete', attributes: { ...this.context.session.toJSON() } },
|
|
130
130
|
(span) => this._respondToWriteIds(() => this.store.deleteSome(ids, span), span)
|
|
131
131
|
)
|
|
132
132
|
}
|
|
@@ -43,7 +43,12 @@ export default class SyncRetry {
|
|
|
43
43
|
|
|
44
44
|
attempt++
|
|
45
45
|
|
|
46
|
-
const spanOptions = {
|
|
46
|
+
const spanOptions = {
|
|
47
|
+
...spanOpts,
|
|
48
|
+
name: `${spanOpts.name}:attempt:${attempt}/${this.MAX_ATTEMPTS}`,
|
|
49
|
+
op: `${spanOpts.op}:attempt`,
|
|
50
|
+
attributes: { ...spanOpts.attributes, attempt, ...this.context.session.toJSON() }
|
|
51
|
+
}
|
|
47
52
|
const result = await this.telemetry.trace(spanOptions, span => {
|
|
48
53
|
if (!this.context.connectivity.getValue()) {
|
|
49
54
|
this.telemetry.debug('[Retry] No connectivity - skipping')
|
|
@@ -100,7 +100,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
100
100
|
async requestSync(reason: string) {
|
|
101
101
|
inBoundary(ctx => {
|
|
102
102
|
this.telemetry.trace(
|
|
103
|
-
{ name: `sync:${this.model.table}`, op: 'sync', attributes: ctx },
|
|
103
|
+
{ name: `sync:${this.model.table}`, op: 'sync', attributes: { ...ctx, ...this.context.session.toJSON() } },
|
|
104
104
|
async span => {
|
|
105
105
|
let pushError: any = null
|
|
106
106
|
|
|
@@ -125,7 +125,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
125
125
|
async requestPush(reason: string) {
|
|
126
126
|
inBoundary(ctx => {
|
|
127
127
|
this.telemetry.trace(
|
|
128
|
-
{ name: `sync:${this.model.table}`, op: 'push', attributes: ctx },
|
|
128
|
+
{ name: `sync:${this.model.table}`, op: 'push', attributes: { ...ctx, ...this.context.session.toJSON() } },
|
|
129
129
|
async span => {
|
|
130
130
|
await this.pushUnsyncedWithRetry(span)
|
|
131
131
|
}
|
|
@@ -509,7 +509,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
509
509
|
{
|
|
510
510
|
name: `pull:${this.model.table}:run`,
|
|
511
511
|
op: 'pull:run',
|
|
512
|
-
attributes: { table: this.model.table },
|
|
512
|
+
attributes: { table: this.model.table, ...this.context.session.toJSON() },
|
|
513
513
|
parentSpan: span,
|
|
514
514
|
},
|
|
515
515
|
async (pullSpan) => {
|
|
@@ -519,7 +519,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
519
519
|
{
|
|
520
520
|
name: `pull:${this.model.table}:run:fetch`,
|
|
521
521
|
op: 'pull:run:fetch',
|
|
522
|
-
attributes: { lastFetchToken: lastFetchToken ?? undefined },
|
|
522
|
+
attributes: { lastFetchToken: lastFetchToken ?? undefined, ...this.context.session.toJSON() },
|
|
523
523
|
parentSpan: pullSpan,
|
|
524
524
|
},
|
|
525
525
|
() => this.puller(this.context.session, lastFetchToken, this.runScope.signal)
|
|
@@ -542,7 +542,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
542
542
|
{
|
|
543
543
|
name: `push:${this.model.table}`,
|
|
544
544
|
op: 'push:run',
|
|
545
|
-
attributes: { table: this.model.table },
|
|
545
|
+
attributes: { table: this.model.table, ...this.context.session.toJSON() },
|
|
546
546
|
parentSpan,
|
|
547
547
|
},
|
|
548
548
|
async (pushSpan) => {
|
|
@@ -552,6 +552,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
552
552
|
{
|
|
553
553
|
name: `push:${this.model.table}:run:fetch`,
|
|
554
554
|
op: 'push:run:fetch',
|
|
555
|
+
attributes: { ...this.context.session.toJSON() },
|
|
555
556
|
parentSpan: pushSpan,
|
|
556
557
|
},
|
|
557
558
|
() => this.pusher(this.context.session, payload, this.runScope.signal)
|
|
@@ -706,7 +707,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
706
707
|
work: (writer: WriterInterface) => Promise<T>
|
|
707
708
|
): Promise<T> {
|
|
708
709
|
return this.telemetry.trace(
|
|
709
|
-
{ name: `write:${this.model.table}`, op: 'write', parentSpan },
|
|
710
|
+
{ name: `write:${this.model.table}`, op: 'write', parentSpan, attributes: { ...this.context.session.toJSON() } },
|
|
710
711
|
(writeSpan) => {
|
|
711
712
|
return this.db.write(writer =>
|
|
712
713
|
this.telemetry.trace(
|
|
@@ -714,6 +715,7 @@ export default class SyncStore<TModel extends BaseModel = BaseModel> {
|
|
|
714
715
|
name: `write:generate:${this.model.table}`,
|
|
715
716
|
op: 'write:generate',
|
|
716
717
|
parentSpan: writeSpan,
|
|
718
|
+
attributes: { ...this.context.session.toJSON() },
|
|
717
719
|
},
|
|
718
720
|
() => work(writer)
|
|
719
721
|
)
|
|
@@ -36,9 +36,7 @@ export const syncSentryBeforeSendTransaction: ReturnsUndefined<NonNullable<Sentr
|
|
|
36
36
|
return undefined
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
// so we have to make consumers pass in our greedy option
|
|
41
|
-
export const createSyncSentryTracesSampler = () => {
|
|
39
|
+
export const createSyncSentryTracesSampler = (sampleRate = 0.1) => {
|
|
42
40
|
const sampler: ReturnsUndefined<NonNullable<SentryBrowserOptions['tracesSampler']>> = (context) => {
|
|
43
41
|
if (!context.name.startsWith(SYNC_TELEMETRY_TRACE_PREFIX)) {
|
|
44
42
|
return undefined
|
|
@@ -51,7 +49,7 @@ export const createSyncSentryTracesSampler = () => {
|
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
if (attributes?.userId) {
|
|
54
|
-
return userBucketedSampler(attributes.userId as string | number,
|
|
52
|
+
return userBucketedSampler(attributes.userId as string | number, sampleRate)
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
return undefined
|