Skip to content

Commit c164926

Browse files
committed
fixup: move the read preference defaulting to the data service
1 parent 3926c4f commit c164926

File tree

5 files changed

+75
-22
lines changed

5 files changed

+75
-22
lines changed

packages/compass-schema/src/modules/schema-analysis.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export const analyzeSchema = async (
6464
},
6565
{
6666
abortSignal,
67+
fallbackReadPreference: 'secondaryPreferred',
6768
}
6869
);
6970
const schemaData = await mongodbSchema(docs);

packages/compass-schema/src/stores/reducer.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { Schema } from 'mongodb-schema';
22
import type { Action, AnyAction, Reducer } from 'redux';
3-
import ConnectionString from 'mongodb-connection-string-url';
43
import type { AggregateOptions } from 'mongodb';
54
import { type AnalysisState } from '../constants/analysis-states';
65
import {
@@ -214,12 +213,6 @@ export const stopAnalysis = (): SchemaThunkAction<void> => {
214213
};
215214
};
216215

217-
function isReadPreferenceSet(connectionString: string): boolean {
218-
return !!new ConnectionString(connectionString).searchParams.get(
219-
'readPreference'
220-
);
221-
}
222-
223216
export const startAnalysis = (): SchemaThunkAction<
224217
Promise<void>,
225218
AnalysisStartedAction | AnalysisFinishedAction | AnalysisFailedAction
@@ -260,16 +253,6 @@ export const startAnalysis = (): SchemaThunkAction<
260253

261254
const driverOptions: AggregateOptions = {
262255
maxTimeMS: capMaxTimeMSAtPreferenceLimit(preferences, query.maxTimeMS),
263-
// When the read preference isn't set in the connection string explicitly,
264-
// then we default to secondaryPreferred to avoid using the primary for
265-
// schema analysis.
266-
...(isReadPreferenceSet(
267-
connectionInfoRef.current.connectionOptions.connectionString
268-
)
269-
? {}
270-
: {
271-
readPreference: 'secondaryPreferred',
272-
}),
273256
};
274257

275258
try {

packages/compass-schema/src/stores/store.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ describe('Schema Store', function () {
123123
expect(store.getState().analysisState).to.equal('initial');
124124
});
125125

126-
it('runs the analysis with read pref secondaryPreferred', async function () {
126+
it('runs the analysis with fallback read pref secondaryPreferred', async function () {
127127
sampleStub.resolves([{ name: 'Hans' }, { name: 'Greta' }]);
128128
await store.dispatch(startAnalysis());
129-
expect(sampleStub.getCall(0).args[2])
130-
.property('readPreference')
129+
expect(sampleStub.getCall(0).args[3])
130+
.property('fallbackReadPreference')
131131
.to.equal('secondaryPreferred');
132132
});
133133
});

packages/data-service/src/data-service.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Collection, MongoServerError } from 'mongodb';
77
import { MongoClient } from 'mongodb';
88
import { Int32, UUID } from 'bson';
99
import sinon from 'sinon';
10+
import ConnectionStringUrl from 'mongodb-connection-string-url';
1011
import type { DataService } from './data-service';
1112
import { DataServiceImpl } from './data-service';
1213
import type {
@@ -866,6 +867,54 @@ describe('DataService', function () {
866867
{ allowDiskUse: false }
867868
);
868869
});
870+
871+
it('allows to pass fallbackReadPreference and sets the read preference when unset', function () {
872+
sandbox.spy(dataService, 'aggregate');
873+
void dataService.sample(
874+
'db.coll',
875+
{},
876+
{},
877+
{
878+
fallbackReadPreference: 'secondaryPreferred',
879+
}
880+
);
881+
882+
// eslint-disable-next-line @typescript-eslint/unbound-method
883+
expect(dataService.aggregate).to.have.been.calledWith(
884+
'db.coll',
885+
[{ $sample: { size: 1000 } }],
886+
{ allowDiskUse: true, readPreference: 'secondaryPreferred' }
887+
);
888+
});
889+
890+
it('allows to pass fallbackReadPreference and does not set the read preference when it is already set', function () {
891+
sandbox.spy(dataService, 'aggregate');
892+
const connectionStringReplacement = new ConnectionStringUrl(
893+
cluster().connectionString
894+
);
895+
connectionStringReplacement.searchParams.set(
896+
'readPreference',
897+
'primary'
898+
);
899+
sandbox.replace(dataService as any, '_connectionOptions', {
900+
connectionString: connectionStringReplacement.toString(),
901+
});
902+
void dataService.sample(
903+
'db.coll',
904+
{},
905+
{},
906+
{
907+
fallbackReadPreference: 'secondaryPreferred',
908+
}
909+
);
910+
911+
// eslint-disable-next-line @typescript-eslint/unbound-method
912+
expect(dataService.aggregate).to.have.been.calledWith(
913+
'db.coll',
914+
[{ $sample: { size: 1000 } }],
915+
{ allowDiskUse: true }
916+
);
917+
});
869918
});
870919

871920
describe('#getLastSeenTopology', function () {

packages/data-service/src/data-service.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import type {
5151
ClientEncryptionDataKeyProvider,
5252
ClientEncryptionCreateDataKeyProviderOptions,
5353
SearchIndexDescription,
54+
ReadPreferenceMode,
5455
} from 'mongodb';
5556
import ConnectionStringUrl from 'mongodb-connection-string-url';
5657
import parseNamespace from 'mongodb-ns';
@@ -122,6 +123,12 @@ function isEmptyObject(obj: Record<string, unknown>) {
122123
return Object.keys(obj).length === 0;
123124
}
124125

126+
function isReadPreferenceSet(connectionString: string): boolean {
127+
return !!new ConnectionStringUrl(connectionString).searchParams.get(
128+
'readPreference'
129+
);
130+
}
131+
125132
let id = 0;
126133

127134
type ClientType = 'CRUD' | 'META';
@@ -661,7 +668,9 @@ export interface DataService {
661668
ns: string,
662669
args?: { query?: Filter<Document>; size?: number; fields?: Document },
663670
options?: AggregateOptions,
664-
executionOptions?: ExecutionOptions
671+
executionOptions?: ExecutionOptions & {
672+
fallbackReadPreference: ReadPreferenceMode;
673+
}
665674
): Promise<Document[]>;
666675

667676
/*** Insert ***/
@@ -2182,7 +2191,9 @@ class DataServiceImpl extends WithLogContext implements DataService {
21822191
fields,
21832192
}: { query?: Filter<Document>; size?: number; fields?: Document } = {},
21842193
options: AggregateOptions = {},
2185-
executionOptions?: ExecutionOptions
2194+
executionOptions?: ExecutionOptions & {
2195+
fallbackReadPreference?: ReadPreferenceMode;
2196+
}
21862197
): Promise<Document[]> {
21872198
const pipeline = [];
21882199
if (query && Object.keys(query).length > 0) {
@@ -2209,6 +2220,15 @@ class DataServiceImpl extends WithLogContext implements DataService {
22092220
pipeline,
22102221
{
22112222
allowDiskUse: true,
2223+
// When the read preference isn't set in the connection string explicitly,
2224+
// then we allow consumers to default to a read preference, for instance
2225+
// secondaryPreferred to avoid using the primary for analyzing documents.
2226+
...(executionOptions?.fallbackReadPreference &&
2227+
!isReadPreferenceSet(this._connectionOptions.connectionString)
2228+
? {
2229+
readPreference: executionOptions?.fallbackReadPreference,
2230+
}
2231+
: {}),
22122232
...options,
22132233
},
22142234
executionOptions

0 commit comments

Comments
 (0)