@memberjunction/server 2.110.0 → 2.111.0

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.
@@ -12,309 +12,309 @@ import { mj_core_schema } from '../config.js';
12
12
  * Implements BaseSingleton pattern for cross-instance synchronization
13
13
  */
14
14
  export class LearningCycleScheduler extends BaseSingleton<LearningCycleScheduler> {
15
- private intervalId: NodeJS.Timeout | null = null;
15
+ // private intervalId: NodeJS.Timeout | null = null;
16
16
 
17
- // Track executions by organization ID instead of a global flag
18
- private runningOrganizations: Map<string, { startTime: Date, learningCycleId: string }> = new Map();
17
+ // // Track executions by organization ID instead of a global flag
18
+ // private runningOrganizations: Map<string, { startTime: Date, learningCycleId: string }> = new Map();
19
19
 
20
- private lastRunTime: Date | null = null;
21
- private dataSources: DataSourceInfo[] = [];
20
+ // private lastRunTime: Date | null = null;
21
+ // private dataSources: DataSourceInfo[] = [];
22
22
 
23
- // Protected constructor to enforce singleton pattern via BaseSingleton
24
- protected constructor() {
25
- super();
26
- }
23
+ // // Protected constructor to enforce singleton pattern via BaseSingleton
24
+ // protected constructor() {
25
+ // super();
26
+ // }
27
27
 
28
- public static get Instance(): LearningCycleScheduler {
29
- return super.getInstance<LearningCycleScheduler>();
30
- }
28
+ // public static get Instance(): LearningCycleScheduler {
29
+ // return super.getInstance<LearningCycleScheduler>();
30
+ // }
31
31
 
32
- /**
33
- * Set the data sources for the scheduler
34
- * @param dataSources Array of data sources
35
- */
36
- public setDataSources(dataSources: DataSourceInfo[]): void {
37
- this.dataSources = dataSources;
38
- }
32
+ // /**
33
+ // * Set the data sources for the scheduler
34
+ // * @param dataSources Array of data sources
35
+ // */
36
+ // public setDataSources(dataSources: DataSourceInfo[]): void {
37
+ // this.dataSources = dataSources;
38
+ // }
39
39
 
40
- /**
41
- * Start the scheduler with the specified interval in minutes
42
- * @param intervalMinutes The interval in minutes between runs
43
- * @param skipLearningAPIurl The URL for the learning cycle API endpoint
44
- */
45
- public start(intervalMinutes: number = 60): void {
46
- LogStatus(`Starting learning cycle scheduler with interval of ${intervalMinutes} minutes`);
40
+ // /**
41
+ // * Start the scheduler with the specified interval in minutes
42
+ // * @param intervalMinutes The interval in minutes between runs
43
+ // * @param skipLearningAPIurl The URL for the learning cycle API endpoint
44
+ // */
45
+ // public start(intervalMinutes: number = 60): void {
46
+ // LogStatus(`Starting learning cycle scheduler with interval of ${intervalMinutes} minutes`);
47
47
 
48
- // Set up the interval for recurring calls
49
- const intervalMs = intervalMinutes * 60 * 1000;
50
- this.intervalId = setInterval(() => {
51
- this.runLearningCycle()
52
- .catch(error => LogError(`Error in scheduled learning cycle: ${error}`));
53
- }, intervalMs);
48
+ // // Set up the interval for recurring calls
49
+ // const intervalMs = intervalMinutes * 60 * 1000;
50
+ // this.intervalId = setInterval(() => {
51
+ // this.runLearningCycle()
52
+ // .catch(error => LogError(`Error in scheduled learning cycle: ${error}`));
53
+ // }, intervalMs);
54
54
 
55
- // Start learning cycle immediately upon the server start
56
- this.runLearningCycle()
57
- .catch(error => LogError(`Error in initial learning cycle: ${error}`));
58
- }
55
+ // // Start learning cycle immediately upon the server start
56
+ // this.runLearningCycle()
57
+ // .catch(error => LogError(`Error in initial learning cycle: ${error}`));
58
+ // }
59
59
 
60
- /**
61
- * Stop the scheduler
62
- */
63
- public stop(): void {
64
- if (this.intervalId) {
65
- clearInterval(this.intervalId);
66
- this.intervalId = null;
67
- LogStatus('Learning cycle scheduler stopped');
68
- }
69
- }
60
+ // /**
61
+ // * Stop the scheduler
62
+ // */
63
+ // public stop(): void {
64
+ // if (this.intervalId) {
65
+ // clearInterval(this.intervalId);
66
+ // this.intervalId = null;
67
+ // LogStatus('Learning cycle scheduler stopped');
68
+ // }
69
+ // }
70
70
 
71
- /**
72
- * Run the learning cycle if it's not already running
73
- * @returns A promise that resolves when the learning cycle completes
74
- */
75
- public async runLearningCycle(): Promise<boolean> {
76
- const startTime = new Date();
71
+ // /**
72
+ // * Run the learning cycle if it's not already running
73
+ // * @returns A promise that resolves when the learning cycle completes
74
+ // */
75
+ // public async runLearningCycle(): Promise<boolean> {
76
+ // const startTime = new Date();
77
77
 
78
- try {
79
- // Make sure we have data sources
80
- if (!this.dataSources || this.dataSources.length === 0) {
81
- throw new Error('No data sources available for the learning cycle');
82
- }
78
+ // try {
79
+ // // Make sure we have data sources
80
+ // if (!this.dataSources || this.dataSources.length === 0) {
81
+ // throw new Error('No data sources available for the learning cycle');
82
+ // }
83
83
 
84
- const dataSource = GetReadWriteDataSource(this.dataSources);
84
+ // const dataSource = GetReadWriteDataSource(this.dataSources);
85
85
 
86
- // Get system user for operation
87
- const systemUser = await getSystemUser(dataSource);
88
- if (!systemUser) {
89
- throw new Error('System user not found');
90
- }
86
+ // // Get system user for operation
87
+ // const systemUser = await getSystemUser(dataSource);
88
+ // if (!systemUser) {
89
+ // throw new Error('System user not found');
90
+ // }
91
91
 
92
- // Create context for the resolver
93
- const config = new SQLServerProviderConfigData(dataSource, mj_core_schema, 0, undefined, undefined, false);
94
- const p = new SQLServerDataProvider();
95
- await p.Config(config);
92
+ // // Create context for the resolver
93
+ // const config = new SQLServerProviderConfigData(dataSource, mj_core_schema, 0, undefined, undefined, false);
94
+ // const p = new SQLServerDataProvider();
95
+ // await p.Config(config);
96
96
 
97
- const context: AppContext = {
98
- dataSource: dataSource,
99
- dataSources: this.dataSources,
100
- userPayload: {
101
- email: systemUser.Email,
102
- sessionId: `scheduler_${Date.now()}`,
103
- userRecord: systemUser,
104
- isSystemUser: true
105
- },
106
- providers: [{provider: p, type: 'Read-Write'}]
107
- };
97
+ // const context: AppContext = {
98
+ // dataSource: dataSource,
99
+ // dataSources: this.dataSources,
100
+ // userPayload: {
101
+ // email: systemUser.Email,
102
+ // sessionId: `scheduler_${Date.now()}`,
103
+ // userRecord: systemUser,
104
+ // isSystemUser: true
105
+ // },
106
+ // providers: [{provider: p, type: 'Read-Write'}]
107
+ // };
108
108
 
109
- // Execute the learning cycle
110
- const skipResolver = new AskSkipResolver();
111
- const result = await skipResolver.ExecuteAskSkipLearningCycle(
112
- context,
113
- false // forceEntityRefresh
114
- );
109
+ // // Execute the learning cycle
110
+ // const skipResolver = new AskSkipResolver();
111
+ // const result = await skipResolver.ExecuteAskSkipLearningCycle(
112
+ // context,
113
+ // false // forceEntityRefresh
114
+ // );
115
115
 
116
- const endTime = new Date();
117
- const elapsedMs = endTime.getTime() - startTime.getTime();
116
+ // const endTime = new Date();
117
+ // const elapsedMs = endTime.getTime() - startTime.getTime();
118
118
 
119
- this.lastRunTime = startTime;
119
+ // this.lastRunTime = startTime;
120
120
 
121
- if (result.learningCycleSkipped) {
122
- // skipped the learning cycle - no messages to process, already logged..
123
- return true;
124
- }
125
- else if (result.success) {
126
- LogStatus(`Learning cycle completed successfully in ${elapsedMs}ms`);
127
- return true;
128
- }
129
- else {
130
- LogError(`Learning cycle failed after ${elapsedMs}ms: ${result.error}`);
131
- return false;
132
- }
133
- } catch (error) {
134
- LogError(`Error executing learning cycle: ${error}`);
135
- return false;
136
- }
137
- }
121
+ // if (result.learningCycleSkipped) {
122
+ // // skipped the learning cycle - no messages to process, already logged..
123
+ // return true;
124
+ // }
125
+ // else if (result.success) {
126
+ // LogStatus(`Learning cycle completed successfully in ${elapsedMs}ms`);
127
+ // return true;
128
+ // }
129
+ // else {
130
+ // LogError(`Learning cycle failed after ${elapsedMs}ms: ${result.error}`);
131
+ // return false;
132
+ // }
133
+ // } catch (error) {
134
+ // LogError(`Error executing learning cycle: ${error}`);
135
+ // return false;
136
+ // }
137
+ // }
138
138
 
139
- /**
140
- * Get the current status of the scheduler
141
- */
142
- public getStatus() {
143
- return {
144
- isSchedulerRunning: this.intervalId !== null,
145
- lastRunTime: this.lastRunTime,
146
- runningOrganizations: Array.from(this.runningOrganizations.entries()).map(([orgId, info]) => ({
147
- organizationId: orgId,
148
- learningCycleId: info.learningCycleId,
149
- startTime: info.startTime,
150
- runningForMinutes: (new Date().getTime() - info.startTime.getTime()) / (1000 * 60)
151
- }))
152
- };
153
- }
139
+ // /**
140
+ // * Get the current status of the scheduler
141
+ // */
142
+ // public getStatus() {
143
+ // return {
144
+ // isSchedulerRunning: this.intervalId !== null,
145
+ // lastRunTime: this.lastRunTime,
146
+ // runningOrganizations: Array.from(this.runningOrganizations.entries()).map(([orgId, info]) => ({
147
+ // organizationId: orgId,
148
+ // learningCycleId: info.learningCycleId,
149
+ // startTime: info.startTime,
150
+ // runningForMinutes: (new Date().getTime() - info.startTime.getTime()) / (1000 * 60)
151
+ // }))
152
+ // };
153
+ // }
154
154
 
155
- /**
156
- * Checks if an organization is currently running a learning cycle
157
- * @param organizationId The organization ID to check
158
- * @returns Whether the organization is running a cycle and details if running
159
- */
160
- public isOrganizationRunningCycle(
161
- organizationId: string
162
- ): { isRunning: boolean, startTime?: Date, learningCycleId?: string, runningForMinutes?: number } {
163
- const runningInfo = this.runningOrganizations.get(organizationId);
155
+ // /**
156
+ // * Checks if an organization is currently running a learning cycle
157
+ // * @param organizationId The organization ID to check
158
+ // * @returns Whether the organization is running a cycle and details if running
159
+ // */
160
+ // public isOrganizationRunningCycle(
161
+ // organizationId: string
162
+ // ): { isRunning: boolean, startTime?: Date, learningCycleId?: string, runningForMinutes?: number } {
163
+ // const runningInfo = this.runningOrganizations.get(organizationId);
164
164
 
165
- if (runningInfo) {
166
- // Check if it's been running too long and should be considered stalled
167
- const now = new Date();
168
- const elapsedMinutes = (now.getTime() - runningInfo.startTime.getTime()) / (1000 * 60);
165
+ // if (runningInfo) {
166
+ // // Check if it's been running too long and should be considered stalled
167
+ // const now = new Date();
168
+ // const elapsedMinutes = (now.getTime() - runningInfo.startTime.getTime()) / (1000 * 60);
169
169
 
170
- return {
171
- isRunning: true,
172
- startTime: runningInfo.startTime,
173
- learningCycleId: runningInfo.learningCycleId,
174
- runningForMinutes: elapsedMinutes
175
- };
176
- }
170
+ // return {
171
+ // isRunning: true,
172
+ // startTime: runningInfo.startTime,
173
+ // learningCycleId: runningInfo.learningCycleId,
174
+ // runningForMinutes: elapsedMinutes
175
+ // };
176
+ // }
177
177
 
178
- return { isRunning: false };
179
- }
178
+ // return { isRunning: false };
179
+ // }
180
180
 
181
- /**
182
- * Registers an organization as running a learning cycle
183
- * @param organizationId The organization ID to register
184
- * @param learningCycleId The ID of the learning cycle
185
- * @returns true if successfully registered, false if already running
186
- */
187
- public registerRunningCycle(organizationId: string, learningCycleId: string): boolean {
188
- // First check if already running
189
- const { isRunning } = this.isOrganizationRunningCycle(organizationId);
181
+ // /**
182
+ // * Registers an organization as running a learning cycle
183
+ // * @param organizationId The organization ID to register
184
+ // * @param learningCycleId The ID of the learning cycle
185
+ // * @returns true if successfully registered, false if already running
186
+ // */
187
+ // public registerRunningCycle(organizationId: string, learningCycleId: string): boolean {
188
+ // // First check if already running
189
+ // const { isRunning } = this.isOrganizationRunningCycle(organizationId);
190
190
 
191
- if (isRunning) {
192
- return false;
193
- }
191
+ // if (isRunning) {
192
+ // return false;
193
+ // }
194
194
 
195
- // Register the organization as running a cycle
196
- this.runningOrganizations.set(organizationId, {
197
- startTime: new Date(),
198
- learningCycleId
199
- });
195
+ // // Register the organization as running a cycle
196
+ // this.runningOrganizations.set(organizationId, {
197
+ // startTime: new Date(),
198
+ // learningCycleId
199
+ // });
200
200
 
201
- return true;
202
- }
201
+ // return true;
202
+ // }
203
203
 
204
- /**
205
- * Unregisters an organization after its learning cycle completes
206
- * @param organizationId The organization ID to unregister
207
- * @returns true if successfully unregistered, false if wasn't registered
208
- */
209
- public unregisterRunningCycle(organizationId: string): boolean {
210
- if (this.runningOrganizations.has(organizationId)) {
211
- this.runningOrganizations.delete(organizationId);
212
- return true;
213
- }
204
+ // /**
205
+ // * Unregisters an organization after its learning cycle completes
206
+ // * @param organizationId The organization ID to unregister
207
+ // * @returns true if successfully unregistered, false if wasn't registered
208
+ // */
209
+ // public unregisterRunningCycle(organizationId: string): boolean {
210
+ // if (this.runningOrganizations.has(organizationId)) {
211
+ // this.runningOrganizations.delete(organizationId);
212
+ // return true;
213
+ // }
214
214
 
215
- return false;
216
- }
215
+ // return false;
216
+ // }
217
217
 
218
- /**
219
- * Manually execute a learning cycle run for testing purposes
220
- * This is intended for debugging/testing only and will force a run
221
- * even if the scheduler is not started
222
- * @param organizationId Optional organization ID to register for the manual run
223
- * @returns A promise that resolves when the learning cycle completes
224
- */
225
- public async manuallyExecuteLearningCycle(organizationId?: string): Promise<boolean> {
226
- try {
227
- LogStatus('🧪 Manually executing learning cycle for testing...');
218
+ // /**
219
+ // * Manually execute a learning cycle run for testing purposes
220
+ // * This is intended for debugging/testing only and will force a run
221
+ // * even if the scheduler is not started
222
+ // * @param organizationId Optional organization ID to register for the manual run
223
+ // * @returns A promise that resolves when the learning cycle completes
224
+ // */
225
+ // public async manuallyExecuteLearningCycle(organizationId?: string): Promise<boolean> {
226
+ // try {
227
+ // LogStatus('🧪 Manually executing learning cycle for testing...');
228
228
 
229
- // If an organization ID is provided, register it as running
230
- const learningCycleId = `manual_${Date.now()}`;
231
- let orgRegistered = false;
229
+ // // If an organization ID is provided, register it as running
230
+ // const learningCycleId = `manual_${Date.now()}`;
231
+ // let orgRegistered = false;
232
232
 
233
- if (organizationId) {
234
- // Check if already running
235
- const runningStatus = this.isOrganizationRunningCycle(organizationId);
233
+ // if (organizationId) {
234
+ // // Check if already running
235
+ // const runningStatus = this.isOrganizationRunningCycle(organizationId);
236
236
 
237
- if (runningStatus.isRunning) {
238
- LogError(`Organization ${organizationId} is already running a learning cycle. Cannot start a new one.`);
239
- return false;
240
- }
237
+ // if (runningStatus.isRunning) {
238
+ // LogError(`Organization ${organizationId} is already running a learning cycle. Cannot start a new one.`);
239
+ // return false;
240
+ // }
241
241
 
242
- // Register this organization
243
- orgRegistered = this.registerRunningCycle(organizationId, learningCycleId);
244
- if (!orgRegistered) {
245
- LogError(`Failed to register organization ${organizationId} for manual learning cycle execution`);
246
- return false;
247
- }
248
- }
242
+ // // Register this organization
243
+ // orgRegistered = this.registerRunningCycle(organizationId, learningCycleId);
244
+ // if (!orgRegistered) {
245
+ // LogError(`Failed to register organization ${organizationId} for manual learning cycle execution`);
246
+ // return false;
247
+ // }
248
+ // }
249
249
 
250
- // Run the learning cycle
251
- const result = await this.runLearningCycle();
252
- LogStatus(`🧪 Manual learning cycle execution completed with result: ${result ? 'Success' : 'Failed'}`);
250
+ // // Run the learning cycle
251
+ // const result = await this.runLearningCycle();
252
+ // LogStatus(`🧪 Manual learning cycle execution completed with result: ${result ? 'Success' : 'Failed'}`);
253
253
 
254
- // Unregister the organization if it was registered
255
- if (organizationId && orgRegistered) {
256
- this.unregisterRunningCycle(organizationId);
257
- }
254
+ // // Unregister the organization if it was registered
255
+ // if (organizationId && orgRegistered) {
256
+ // this.unregisterRunningCycle(organizationId);
257
+ // }
258
258
 
259
- return result;
260
- } catch (error) {
261
- // Make sure to unregister on error
262
- if (organizationId && this.runningOrganizations.has(organizationId)) {
263
- this.unregisterRunningCycle(organizationId);
264
- }
259
+ // return result;
260
+ // } catch (error) {
261
+ // // Make sure to unregister on error
262
+ // if (organizationId && this.runningOrganizations.has(organizationId)) {
263
+ // this.unregisterRunningCycle(organizationId);
264
+ // }
265
265
 
266
- LogError(`Error in manual learning cycle execution: ${error}`);
267
- return false;
268
- }
269
- }
266
+ // LogError(`Error in manual learning cycle execution: ${error}`);
267
+ // return false;
268
+ // }
269
+ // }
270
270
 
271
- /**
272
- * Force stop a running learning cycle for an organization
273
- * @param organizationId The organization ID to stop the cycle for
274
- * @returns Information about the stopped cycle
275
- */
276
- public stopLearningCycleForOrganization(organizationId: string): {
277
- success: boolean,
278
- message: string,
279
- wasRunning: boolean,
280
- cycleDetails?: { learningCycleId: string, startTime: Date, runningForMinutes: number }
281
- } {
282
- // Check if this organization has a running cycle
283
- const runningStatus = this.isOrganizationRunningCycle(organizationId);
271
+ // /**
272
+ // * Force stop a running learning cycle for an organization
273
+ // * @param organizationId The organization ID to stop the cycle for
274
+ // * @returns Information about the stopped cycle
275
+ // */
276
+ // public stopLearningCycleForOrganization(organizationId: string): {
277
+ // success: boolean,
278
+ // message: string,
279
+ // wasRunning: boolean,
280
+ // cycleDetails?: { learningCycleId: string, startTime: Date, runningForMinutes: number }
281
+ // } {
282
+ // // Check if this organization has a running cycle
283
+ // const runningStatus = this.isOrganizationRunningCycle(organizationId);
284
284
 
285
- if (!runningStatus.isRunning) {
286
- return {
287
- success: false,
288
- message: `No running learning cycle found for organization ${organizationId}`,
289
- wasRunning: false
290
- };
291
- }
285
+ // if (!runningStatus.isRunning) {
286
+ // return {
287
+ // success: false,
288
+ // message: `No running learning cycle found for organization ${organizationId}`,
289
+ // wasRunning: false
290
+ // };
291
+ // }
292
292
 
293
- // Capture details before unregistering
294
- const startTime = runningStatus.startTime!;
295
- const learningCycleId = runningStatus.learningCycleId!;
296
- const runningForMinutes = runningStatus.runningForMinutes!;
293
+ // // Capture details before unregistering
294
+ // const startTime = runningStatus.startTime!;
295
+ // const learningCycleId = runningStatus.learningCycleId!;
296
+ // const runningForMinutes = runningStatus.runningForMinutes!;
297
297
 
298
- // Unregister the organization
299
- const unregistered = this.unregisterRunningCycle(organizationId);
298
+ // // Unregister the organization
299
+ // const unregistered = this.unregisterRunningCycle(organizationId);
300
300
 
301
- if (unregistered) {
302
- return {
303
- success: true,
304
- message: `Successfully stopped learning cycle for organization ${organizationId}`,
305
- wasRunning: true,
306
- cycleDetails: {
307
- learningCycleId,
308
- startTime,
309
- runningForMinutes
310
- }
311
- };
312
- } else {
313
- return {
314
- success: false,
315
- message: `Failed to stop learning cycle for organization ${organizationId}`,
316
- wasRunning: true
317
- };
318
- }
319
- }
301
+ // if (unregistered) {
302
+ // return {
303
+ // success: true,
304
+ // message: `Successfully stopped learning cycle for organization ${organizationId}`,
305
+ // wasRunning: true,
306
+ // cycleDetails: {
307
+ // learningCycleId,
308
+ // startTime,
309
+ // runningForMinutes
310
+ // }
311
+ // };
312
+ // } else {
313
+ // return {
314
+ // success: false,
315
+ // message: `Failed to stop learning cycle for organization ${organizationId}`,
316
+ // wasRunning: true
317
+ // };
318
+ // }
319
+ // }
320
320
  }