@joystick.js/db-canary 0.0.0-canary.2274 → 0.0.0-canary.2276
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/README.md +87 -104
- package/debug_test_runner.js +208 -0
- package/dist/client/index.js +1 -1
- package/dist/server/cluster/master.js +2 -2
- package/dist/server/cluster/worker.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/lib/auto_index_manager.js +1 -1
- package/dist/server/lib/bulk_insert_optimizer.js +1 -1
- package/dist/server/lib/http_server.js +3 -3
- package/dist/server/lib/operation_dispatcher.js +1 -1
- package/dist/server/lib/operations/admin.js +1 -1
- package/dist/server/lib/operations/update_one.js +1 -1
- package/dist/server/lib/simple_sync_manager.js +1 -0
- package/dist/server/lib/sync_receiver.js +1 -0
- package/full_debug_test_runner.js +197 -0
- package/package.json +10 -7
- package/src/client/index.js +1 -0
- package/src/server/cluster/master.js +8 -2
- package/src/server/cluster/worker.js +9 -3
- package/src/server/index.js +25 -24
- package/src/server/lib/auto_index_manager.js +8 -3
- package/src/server/lib/bulk_insert_optimizer.js +79 -0
- package/src/server/lib/http_server.js +7 -0
- package/src/server/lib/operation_dispatcher.js +16 -10
- package/src/server/lib/operations/admin.js +64 -31
- package/src/server/lib/operations/update_one.js +251 -1
- package/src/server/lib/simple_sync_manager.js +444 -0
- package/src/server/lib/sync_receiver.js +461 -0
- package/tests/client/index.test.js +7 -0
- package/tests/performance/isolated_5000000_test.js +184 -0
- package/tests/server/lib/http_server.test.js +3 -12
- package/tests/server/lib/operations/update_one.test.js +161 -0
- package/tests/server/lib/simple_sync_system.test.js +124 -0
- package/dist/server/lib/replication_manager.js +0 -1
- package/dist/server/lib/write_forwarder.js +0 -1
- package/src/server/lib/replication_manager.js +0 -727
- package/src/server/lib/write_forwarder.js +0 -636
- package/tests/server/lib/replication_manager.test.js +0 -202
- package/tests/server/lib/write_forwarder.test.js +0 -258
package/package.json
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joystick.js/db-canary",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-canary.
|
|
5
|
-
"canary_version": "0.0.0-canary.
|
|
4
|
+
"version": "0.0.0-canary.2276",
|
|
5
|
+
"canary_version": "0.0.0-canary.2275",
|
|
6
6
|
"description": "JoystickDB - A minimalist database server for the Joystick framework",
|
|
7
7
|
"main": "./dist/server/index.js",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "node ./.build/index.js",
|
|
10
10
|
"release": "node increment_version.js && npm run build && npm publish",
|
|
11
11
|
"start": "node src/server/index.js",
|
|
12
|
-
"test": "NODE_ENV=test
|
|
12
|
+
"test": "NODE_ENV=test node test_runner.js core",
|
|
13
13
|
"test:watch": "NODE_ENV=test ava --watch",
|
|
14
|
-
"test:performance": "NODE_ENV=test
|
|
15
|
-
"test:enterprise": "NODE_ENV=test
|
|
16
|
-
"test:benchmarks": "NODE_ENV=test
|
|
17
|
-
"test:1m": "NODE_ENV=test
|
|
14
|
+
"test:performance": "NODE_ENV=test node test_runner.js bulk",
|
|
15
|
+
"test:enterprise": "NODE_ENV=test node test_runner.js enterprise",
|
|
16
|
+
"test:benchmarks": "NODE_ENV=test node test_runner.js benchmarks",
|
|
17
|
+
"test:1m": "NODE_ENV=test node test_runner.js individual",
|
|
18
18
|
"test:runner": "node test_runner.js",
|
|
19
|
+
"test:safe": "NODE_ENV=test node test_runner.js safe",
|
|
20
|
+
"test:standard": "NODE_ENV=test node test_runner.js standard",
|
|
21
|
+
"test:isolated": "NODE_ENV=test node test_runner.js isolated",
|
|
19
22
|
"build:types": "tsc --declaration --emitDeclarationOnly --allowJs --outDir types src/**/*.js",
|
|
20
23
|
"build:types:client": "tsc --declaration --emitDeclarationOnly --allowJs --outDir types/client src/client/*.js",
|
|
21
24
|
"build:types:server": "tsc --declaration --emitDeclarationOnly --allowJs --outDir types/server src/server/**/*.js"
|
package/src/client/index.js
CHANGED
|
@@ -102,14 +102,20 @@ class ClusterMaster extends EventEmitter {
|
|
|
102
102
|
* @returns {string} Database path
|
|
103
103
|
*/
|
|
104
104
|
get_database_path() {
|
|
105
|
-
let database_path
|
|
105
|
+
let database_path;
|
|
106
106
|
try {
|
|
107
107
|
const settings = get_settings();
|
|
108
108
|
if (settings?.data_path) {
|
|
109
109
|
database_path = settings.data_path;
|
|
110
|
+
} else {
|
|
111
|
+
// NOTE: Use proper .joystick/data path with port number as fallback, matching other database providers
|
|
112
|
+
const { tcp_port } = get_port_configuration();
|
|
113
|
+
database_path = `./.joystick/data/joystickdb_${tcp_port}`;
|
|
110
114
|
}
|
|
111
115
|
} catch (error) {
|
|
112
|
-
// Settings not available, use default path
|
|
116
|
+
// NOTE: Settings not available, use default path with port from this.port
|
|
117
|
+
const { tcp_port } = get_port_configuration();
|
|
118
|
+
database_path = `./.joystick/data/joystickdb_${tcp_port}`;
|
|
113
119
|
}
|
|
114
120
|
return database_path;
|
|
115
121
|
}
|
|
@@ -99,7 +99,7 @@ class ClusterWorker {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
handle_config(message) {
|
|
102
|
+
async handle_config(message) {
|
|
103
103
|
const incoming_master_id = message.data.master_id;
|
|
104
104
|
|
|
105
105
|
// NOTE: Only handle config from the first master to avoid conflicts between multiple test masters.
|
|
@@ -134,14 +134,20 @@ class ClusterWorker {
|
|
|
134
134
|
// NOTE: Initialize database for read operations in worker process.
|
|
135
135
|
try {
|
|
136
136
|
// NOTE: Initialize database with data_path from settings if available.
|
|
137
|
-
let database_path
|
|
137
|
+
let database_path;
|
|
138
138
|
try {
|
|
139
139
|
const settings = get_settings();
|
|
140
140
|
if (settings?.data_path) {
|
|
141
141
|
database_path = settings.data_path;
|
|
142
|
+
} else {
|
|
143
|
+
// NOTE: Use proper .joystick/data path with port number as fallback, matching other database providers
|
|
144
|
+
const { get_port_configuration } = await import('../lib/load_settings.js');
|
|
145
|
+
const { tcp_port } = get_port_configuration();
|
|
146
|
+
database_path = `./.joystick/data/joystickdb_${tcp_port}`;
|
|
142
147
|
}
|
|
143
148
|
} catch (error) {
|
|
144
|
-
// NOTE: Settings not available, use default path.
|
|
149
|
+
// NOTE: Settings not available, use default path with port from this.port
|
|
150
|
+
database_path = `./.joystick/data/joystickdb_${this.port}`;
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
initialize_database(database_path);
|
package/src/server/index.js
CHANGED
|
@@ -42,13 +42,13 @@ import {
|
|
|
42
42
|
stop_backup_schedule
|
|
43
43
|
} from './lib/backup_manager.js';
|
|
44
44
|
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} from './lib/
|
|
45
|
+
initialize_simple_sync_manager,
|
|
46
|
+
shutdown_simple_sync_manager
|
|
47
|
+
} from './lib/simple_sync_manager.js';
|
|
48
48
|
import {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} from './lib/
|
|
49
|
+
initialize_sync_receiver,
|
|
50
|
+
shutdown_sync_receiver
|
|
51
|
+
} from './lib/sync_receiver.js';
|
|
52
52
|
import { handle_database_operation, handle_admin_operation, handle_ping_operation } from './lib/operation_dispatcher.js';
|
|
53
53
|
import { start_http_server, stop_http_server } from './lib/http_server.js';
|
|
54
54
|
import {
|
|
@@ -326,29 +326,30 @@ const initialize_server_components = async (settings) => {
|
|
|
326
326
|
};
|
|
327
327
|
|
|
328
328
|
/**
|
|
329
|
-
* Initializes
|
|
329
|
+
* Initializes simple sync manager with error handling.
|
|
330
330
|
* @param {Function} log - Logger function
|
|
331
331
|
*/
|
|
332
|
-
const
|
|
332
|
+
const initialize_sync_manager_with_logging = (log) => {
|
|
333
333
|
try {
|
|
334
|
-
|
|
335
|
-
log.info('
|
|
336
|
-
} catch (
|
|
337
|
-
log.warn('Failed to initialize
|
|
334
|
+
initialize_simple_sync_manager();
|
|
335
|
+
log.info('Simple sync manager initialized');
|
|
336
|
+
} catch (sync_error) {
|
|
337
|
+
log.warn('Failed to initialize simple sync manager', { error: sync_error.message });
|
|
338
338
|
}
|
|
339
339
|
};
|
|
340
340
|
|
|
341
341
|
/**
|
|
342
|
-
* Initializes
|
|
342
|
+
* Initializes sync receiver with error handling.
|
|
343
343
|
* @param {Function} log - Logger function
|
|
344
344
|
*/
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
345
|
+
const initialize_sync_receiver_with_logging = (log) => {
|
|
346
|
+
initialize_sync_receiver()
|
|
347
|
+
.then(() => {
|
|
348
|
+
log.info('Sync receiver initialized');
|
|
349
|
+
})
|
|
350
|
+
.catch((receiver_error) => {
|
|
351
|
+
log.warn('Failed to initialize sync receiver', { error: receiver_error.message });
|
|
352
|
+
});
|
|
352
353
|
};
|
|
353
354
|
|
|
354
355
|
/**
|
|
@@ -658,8 +659,8 @@ const create_server_cleanup_function = () => {
|
|
|
658
659
|
try {
|
|
659
660
|
await stop_http_server();
|
|
660
661
|
stop_backup_schedule();
|
|
661
|
-
await
|
|
662
|
-
await
|
|
662
|
+
await shutdown_simple_sync_manager();
|
|
663
|
+
await shutdown_sync_receiver();
|
|
663
664
|
|
|
664
665
|
if (connection_manager) {
|
|
665
666
|
connection_manager.shutdown();
|
|
@@ -699,8 +700,8 @@ export const create_server = async () => {
|
|
|
699
700
|
await attempt_startup_restore(settings, log);
|
|
700
701
|
await initialize_server_components(settings);
|
|
701
702
|
|
|
702
|
-
|
|
703
|
-
|
|
703
|
+
initialize_sync_manager_with_logging(log);
|
|
704
|
+
initialize_sync_receiver_with_logging(log);
|
|
704
705
|
start_backup_scheduling(settings, log);
|
|
705
706
|
|
|
706
707
|
connection_manager = create_server_connection_manager();
|
|
@@ -140,10 +140,15 @@ const extract_query_fields = (filter) => {
|
|
|
140
140
|
return fields;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
try {
|
|
144
|
+
for (const [field, value] of Object.entries(filter)) {
|
|
145
|
+
if (should_monitor_field(field)) {
|
|
146
|
+
fields.push(field);
|
|
147
|
+
}
|
|
146
148
|
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
// Return empty array if filter processing fails
|
|
151
|
+
return [];
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
return fields;
|
|
@@ -306,6 +306,45 @@ const rebuild_collection_indexes = async (database_name, collection_name) => {
|
|
|
306
306
|
});
|
|
307
307
|
};
|
|
308
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Fast path for small document sets without optimization overhead.
|
|
311
|
+
* @param {string} database_name - Database name
|
|
312
|
+
* @param {string} collection_name - Collection name
|
|
313
|
+
* @param {Array<Object>} documents - Documents to insert
|
|
314
|
+
* @returns {Promise<Object>} Bulk insert results
|
|
315
|
+
*/
|
|
316
|
+
const bulk_insert_fast_path = async (database_name, collection_name, documents) => {
|
|
317
|
+
const db = get_database();
|
|
318
|
+
const current_timestamp = new Date().toISOString();
|
|
319
|
+
const inserted_ids = [];
|
|
320
|
+
|
|
321
|
+
await db.transaction(() => {
|
|
322
|
+
for (const doc of documents) {
|
|
323
|
+
const document_id = doc._id || generate_sequential_id();
|
|
324
|
+
|
|
325
|
+
const document_with_timestamps = {
|
|
326
|
+
...doc,
|
|
327
|
+
_id: document_id,
|
|
328
|
+
_created_at: doc._created_at || current_timestamp,
|
|
329
|
+
_updated_at: doc._updated_at || current_timestamp
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const key = build_collection_key(database_name, collection_name, document_id);
|
|
333
|
+
|
|
334
|
+
// Check if document already exists
|
|
335
|
+
const existing = db.get(key);
|
|
336
|
+
if (existing) {
|
|
337
|
+
throw new Error(`Document with _id ${document_id} already exists`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
db.put(key, JSON.stringify(document_with_timestamps));
|
|
341
|
+
inserted_ids.push(document_id);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
return inserted_ids;
|
|
346
|
+
};
|
|
347
|
+
|
|
309
348
|
/**
|
|
310
349
|
* Optimized bulk insert implementation with all performance optimizations.
|
|
311
350
|
* @param {string} database_name - Database name
|
|
@@ -336,6 +375,46 @@ const bulk_insert_optimized = async (database_name, collection_name, documents,
|
|
|
336
375
|
throw new Error('Documents must be a non-empty array');
|
|
337
376
|
}
|
|
338
377
|
|
|
378
|
+
// For small datasets (< 5000 docs), use fast path to avoid optimization overhead
|
|
379
|
+
const use_fast_path = documents.length < 5000;
|
|
380
|
+
|
|
381
|
+
if (use_fast_path) {
|
|
382
|
+
log.debug('Using fast path for small dataset', {
|
|
383
|
+
database: database_name,
|
|
384
|
+
collection: collection_name,
|
|
385
|
+
document_count: documents.length
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
const inserted_ids = await bulk_insert_fast_path(database_name, collection_name, documents);
|
|
390
|
+
|
|
391
|
+
const end_time = Date.now();
|
|
392
|
+
const end_memory = process.memoryUsage();
|
|
393
|
+
|
|
394
|
+
const performance_metrics = {
|
|
395
|
+
duration_ms: end_time - start_time,
|
|
396
|
+
documents_per_second: Math.round(documents.length / ((end_time - start_time) / 1000)),
|
|
397
|
+
memory_delta_mb: Math.round((end_memory.heapUsed - start_memory.heapUsed) / (1024 * 1024)),
|
|
398
|
+
peak_memory_mb: Math.round(end_memory.heapUsed / (1024 * 1024))
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
acknowledged: true,
|
|
403
|
+
inserted_count: inserted_ids.length,
|
|
404
|
+
inserted_ids: inserted_ids,
|
|
405
|
+
performance: performance_metrics
|
|
406
|
+
};
|
|
407
|
+
} catch (error) {
|
|
408
|
+
log.error('Fast path bulk insert failed', {
|
|
409
|
+
database: database_name,
|
|
410
|
+
collection: collection_name,
|
|
411
|
+
error: error.message
|
|
412
|
+
});
|
|
413
|
+
throw error;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Use optimized path for larger datasets
|
|
339
418
|
log.info('Starting optimized bulk insert', {
|
|
340
419
|
database: database_name,
|
|
341
420
|
collection: collection_name,
|
|
@@ -1084,6 +1084,13 @@ const start_http_server = (port = 1984) => {
|
|
|
1084
1084
|
return new Promise((resolve, reject) => {
|
|
1085
1085
|
// NOTE: Set up error handler before calling listen.
|
|
1086
1086
|
server.once('error', (error) => {
|
|
1087
|
+
// NOTE: In test environment, silently fail HTTP server startup to avoid port conflicts.
|
|
1088
|
+
if (process.env.NODE_ENV === 'test') {
|
|
1089
|
+
log.warn('Failed to start HTTP server', { error: error.message });
|
|
1090
|
+
resolve(null);
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1087
1094
|
// NOTE: Clean up on startup failure.
|
|
1088
1095
|
if (setup_required) {
|
|
1089
1096
|
setup_token = null;
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { encode_message } from './tcp_protocol.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { get_simple_sync_manager } from './simple_sync_manager.js';
|
|
11
|
+
import { get_sync_receiver } from './sync_receiver.js';
|
|
12
12
|
import { check_and_grow_map_size } from './query_engine.js';
|
|
13
13
|
import { performance_monitor } from './performance_monitor.js';
|
|
14
14
|
import create_logger from './logger.js';
|
|
@@ -236,17 +236,17 @@ const is_write_operation = (op_type) => {
|
|
|
236
236
|
};
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
|
-
* Queues operation for
|
|
239
|
+
* Queues operation for sync if it's a write operation.
|
|
240
240
|
* @param {string} op_type - Operation type
|
|
241
241
|
* @param {Object} data - Operation data
|
|
242
242
|
*/
|
|
243
|
-
const
|
|
243
|
+
const queue_sync_if_write_operation = (op_type, data) => {
|
|
244
244
|
if (!is_write_operation(op_type)) {
|
|
245
245
|
return;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
const
|
|
249
|
-
|
|
248
|
+
const sync_manager = get_simple_sync_manager();
|
|
249
|
+
sync_manager.queue_sync(op_type, data.collection, data);
|
|
250
250
|
|
|
251
251
|
setImmediate(() => check_and_grow_map_size());
|
|
252
252
|
};
|
|
@@ -292,7 +292,7 @@ const handle_successful_operation = (socket, op_type, data, result, start_time,
|
|
|
292
292
|
response_size
|
|
293
293
|
);
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
queue_sync_if_write_operation(op_type, data);
|
|
296
296
|
};
|
|
297
297
|
|
|
298
298
|
/**
|
|
@@ -364,10 +364,16 @@ export const handle_database_operation = async (socket, op_type, data, check_aut
|
|
|
364
364
|
return;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
const
|
|
368
|
-
const
|
|
367
|
+
const sync_receiver = get_sync_receiver();
|
|
368
|
+
const should_block = sync_receiver.should_block_client_operation(op_type);
|
|
369
369
|
|
|
370
|
-
if (
|
|
370
|
+
if (should_block) {
|
|
371
|
+
const response = {
|
|
372
|
+
ok: 0,
|
|
373
|
+
error: 'Write operations not allowed on secondary node. Use primary node for write operations.'
|
|
374
|
+
};
|
|
375
|
+
send_encoded_response(socket, response);
|
|
376
|
+
log_operation_performance(socket.id, op_type, data.collection, 0, 'error', 'Write operation blocked on secondary', raw_data_size, 0);
|
|
371
377
|
return;
|
|
372
378
|
}
|
|
373
379
|
|
|
@@ -28,8 +28,8 @@ import {
|
|
|
28
28
|
restore_backup,
|
|
29
29
|
cleanup_old_backups
|
|
30
30
|
} from '../backup_manager.js';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
31
|
+
import { get_simple_sync_manager } from '../simple_sync_manager.js';
|
|
32
|
+
import { get_sync_receiver } from '../sync_receiver.js';
|
|
33
33
|
import create_logger from '../logger.js';
|
|
34
34
|
import { performance_monitor } from '../performance_monitor.js';
|
|
35
35
|
|
|
@@ -869,46 +869,79 @@ export default async (admin_action, data = {}, connection_manager, authenticated
|
|
|
869
869
|
result = { indexes: get_indexes(data.database || 'default', data.collection) };
|
|
870
870
|
break;
|
|
871
871
|
|
|
872
|
-
case '
|
|
873
|
-
const
|
|
874
|
-
|
|
872
|
+
case 'get_sync_status':
|
|
873
|
+
const sync_manager = get_simple_sync_manager();
|
|
874
|
+
const sync_receiver = get_sync_receiver();
|
|
875
|
+
result = {
|
|
876
|
+
sync_manager: sync_manager.get_sync_status(),
|
|
877
|
+
sync_receiver: sync_receiver.get_sync_status()
|
|
878
|
+
};
|
|
875
879
|
break;
|
|
876
880
|
|
|
877
|
-
case '
|
|
878
|
-
if (!
|
|
879
|
-
throw new Error('
|
|
881
|
+
case 'update_secondary_nodes':
|
|
882
|
+
if (!Array.isArray(data.secondary_nodes)) {
|
|
883
|
+
throw new Error('secondary_nodes array is required for update_secondary_nodes operation');
|
|
880
884
|
}
|
|
881
|
-
const
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
});
|
|
885
|
+
const update_sync_manager = get_simple_sync_manager();
|
|
886
|
+
update_sync_manager.update_secondary_nodes(data.secondary_nodes);
|
|
887
|
+
result = {
|
|
888
|
+
success: true,
|
|
889
|
+
message: 'Secondary nodes updated successfully',
|
|
890
|
+
secondary_nodes: data.secondary_nodes
|
|
891
|
+
};
|
|
889
892
|
break;
|
|
890
893
|
|
|
891
|
-
case '
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
const remove_replication_manager = get_replication_manager();
|
|
896
|
-
result = remove_replication_manager.remove_secondary(data.secondary_id);
|
|
894
|
+
case 'force_sync':
|
|
895
|
+
const force_sync_manager = get_simple_sync_manager();
|
|
896
|
+
result = await force_sync_manager.force_sync();
|
|
897
897
|
break;
|
|
898
898
|
|
|
899
|
-
case '
|
|
900
|
-
|
|
901
|
-
|
|
899
|
+
case 'set_primary_role':
|
|
900
|
+
if (typeof data.primary !== 'boolean') {
|
|
901
|
+
throw new Error('primary boolean value is required for set_primary_role operation');
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
if (data.primary) {
|
|
905
|
+
// Promoting to primary - stop sync receiver, start sync manager
|
|
906
|
+
const receiver = get_sync_receiver();
|
|
907
|
+
receiver.promote_to_primary();
|
|
908
|
+
result = {
|
|
909
|
+
success: true,
|
|
910
|
+
message: 'Node promoted to primary successfully',
|
|
911
|
+
role: 'primary'
|
|
912
|
+
};
|
|
913
|
+
} else {
|
|
914
|
+
// Demoting to secondary - this would require restart with new config
|
|
915
|
+
result = {
|
|
916
|
+
success: false,
|
|
917
|
+
message: 'Demoting primary to secondary requires server restart with updated configuration',
|
|
918
|
+
role: 'primary'
|
|
919
|
+
};
|
|
920
|
+
}
|
|
902
921
|
break;
|
|
903
922
|
|
|
904
|
-
case '
|
|
905
|
-
const
|
|
906
|
-
|
|
923
|
+
case 'reload_sync_key':
|
|
924
|
+
const key_sync_receiver = get_sync_receiver();
|
|
925
|
+
if (!key_sync_receiver.is_secondary) {
|
|
926
|
+
throw new Error('reload_sync_key can only be used on secondary nodes');
|
|
927
|
+
}
|
|
928
|
+
await key_sync_receiver.reload_api_key();
|
|
929
|
+
result = {
|
|
930
|
+
success: true,
|
|
931
|
+
message: 'API_KEY reloaded successfully'
|
|
932
|
+
};
|
|
907
933
|
break;
|
|
908
934
|
|
|
909
|
-
case '
|
|
910
|
-
const
|
|
911
|
-
|
|
935
|
+
case 'get_secondary_auth_status':
|
|
936
|
+
const auth_sync_manager = get_simple_sync_manager();
|
|
937
|
+
const auth_status = auth_sync_manager.get_sync_status();
|
|
938
|
+
result = {
|
|
939
|
+
secondary_count: auth_status.secondary_count,
|
|
940
|
+
auth_failures: auth_status.stats.auth_failures,
|
|
941
|
+
successful_syncs: auth_status.stats.successful_syncs,
|
|
942
|
+
failed_syncs: auth_status.stats.failed_syncs,
|
|
943
|
+
secondaries: auth_status.secondaries
|
|
944
|
+
};
|
|
912
945
|
break;
|
|
913
946
|
|
|
914
947
|
default:
|