@@ -127,7 +127,7 @@ public void testWithALotOfUsers() throws Exception {
127
127
throw e ;
128
128
}
129
129
}
130
- Thread .sleep (5000 );
130
+ Thread .sleep (1000 );
131
131
}
132
132
}
133
133
@@ -145,6 +145,120 @@ public void testWithALotOfUsers() throws Exception {
145
145
146
146
}
147
147
148
+
149
+ @ Test
150
+ public void testCoreRestartMidImportShouldResultInSuccessfulImport () throws Exception {
151
+ String [] args = { "../" };
152
+
153
+ // set processing thread number
154
+ Utils .setValueInConfig ("bulk_migration_parallelism" , "8" );
155
+ Utils .setValueInConfig ("bulk_migration_batch_size" , "1000" );
156
+ Utils .setValueInConfig ("log_level" , "DEBUG" );
157
+
158
+ TestingProcessManager .TestingProcess process = TestingProcessManager .start (args , true );
159
+ Main main = process .getProcess ();
160
+ setFeatureFlags (main , new EE_FEATURES [] {
161
+ EE_FEATURES .ACCOUNT_LINKING , EE_FEATURES .MULTI_TENANCY , EE_FEATURES .MFA });
162
+ // We are setting a non-zero initial wait for tests to avoid race condition with the beforeTest process that deletes data in the storage layer
163
+ CronTaskTest .getInstance (main ).setInitialWaitTimeInSeconds (ProcessBulkImportUsers .RESOURCE_KEY , 5 );
164
+ CronTaskTest .getInstance (main ).setIntervalInSeconds (ProcessBulkImportUsers .RESOURCE_KEY , 60 );
165
+
166
+ assertNotNull (process .checkOrWaitForEvent (ProcessState .PROCESS_STATE .STARTED ));
167
+
168
+ Cronjobs .addCronjob (main , (ProcessBulkImportUsers ) main .getResourceDistributor ().getResource (new TenantIdentifier (null , null , null ), ProcessBulkImportUsers .RESOURCE_KEY ));
169
+
170
+ int NUMBER_OF_USERS_TO_UPLOAD = 10000 ;
171
+
172
+ if (StorageLayer .getBaseStorage (main ).getType () != STORAGE_TYPE .SQL || StorageLayer .isInMemDb (main )) {
173
+ return ;
174
+ }
175
+
176
+ // Create user roles before inserting bulk users
177
+ {
178
+ UserRoles .createNewRoleOrModifyItsPermissions (main , "role1" , null );
179
+ UserRoles .createNewRoleOrModifyItsPermissions (main , "role2" , null );
180
+ }
181
+
182
+ // upload a bunch of users through the API
183
+ {
184
+ for (int i = 0 ; i < (NUMBER_OF_USERS_TO_UPLOAD / 1000 ); i ++) {
185
+ JsonObject request = generateUsersJson (1000 , i * 1000 ); // API allows 10k users upload at once
186
+ JsonObject response = uploadBulkImportUsersJson (main , request );
187
+ assertEquals ("OK" , response .get ("status" ).getAsString ());
188
+ }
189
+
190
+ }
191
+
192
+ long processingStarted = System .currentTimeMillis ();
193
+ boolean restartHappened = false ;
194
+ // wait for the cron job to process them
195
+ // periodically check the remaining unprocessed users
196
+ // Note1: the cronjob starts the processing automatically
197
+ // Note2: the successfully processed users get deleted from the bulk_import_users table
198
+ {
199
+ long count = NUMBER_OF_USERS_TO_UPLOAD ;
200
+ while (true ) {
201
+ try {
202
+ JsonObject response = loadBulkImportUsersCountWithStatus (main , null );
203
+ assertEquals ("OK" , response .get ("status" ).getAsString ());
204
+ count = response .get ("count" ).getAsLong ();
205
+ int newUsersNumber = loadBulkImportUsersCountWithStatus (main ,
206
+ BulkImportStorage .BULK_IMPORT_USER_STATUS .NEW ).get ("count" ).getAsInt ();
207
+ int processingUsersNumber = loadBulkImportUsersCountWithStatus (main ,
208
+ BulkImportStorage .BULK_IMPORT_USER_STATUS .PROCESSING ).get ("count" ).getAsInt ();
209
+ int failedUsersNumber = loadBulkImportUsersCountWithStatus (main ,
210
+ BulkImportStorage .BULK_IMPORT_USER_STATUS .FAILED ).get ("count" ).getAsInt ();
211
+ count = newUsersNumber + processingUsersNumber ;
212
+ System .out .println ("Remaining users: " + count );
213
+
214
+ if (count == 0 ) {
215
+ break ;
216
+ }
217
+ if ((System .currentTimeMillis () - processingStarted > 10000 ) && !restartHappened ) {
218
+ System .out .println ("Killing core" );
219
+ process .kill (false );
220
+ Utils .setValueInConfig ("bulk_migration_parallelism" , "14" );
221
+ Utils .setValueInConfig ("bulk_migration_batch_size" , "4000" );
222
+ System .out .println ("Started new core" );
223
+ process = TestingProcessManager .start (args , true );
224
+ main = process .getProcess ();
225
+ setFeatureFlags (main , new EE_FEATURES [] {
226
+ EE_FEATURES .ACCOUNT_LINKING , EE_FEATURES .MULTI_TENANCY , EE_FEATURES .MFA });
227
+ // We are setting a non-zero initial wait for tests to avoid race condition with the beforeTest process that deletes data in the storage layer
228
+ CronTaskTest .getInstance (main ).setInitialWaitTimeInSeconds (ProcessBulkImportUsers .RESOURCE_KEY , 5 );
229
+ CronTaskTest .getInstance (main ).setIntervalInSeconds (ProcessBulkImportUsers .RESOURCE_KEY , 60 );
230
+
231
+ assertNotNull (process .checkOrWaitForEvent (ProcessState .PROCESS_STATE .STARTED ));
232
+
233
+ Cronjobs .addCronjob (main , (ProcessBulkImportUsers ) main .getResourceDistributor ().getResource (new TenantIdentifier (null , null , null ), ProcessBulkImportUsers .RESOURCE_KEY ));
234
+ restartHappened = true ;
235
+ }
236
+ } catch (Exception e ) {
237
+ if (e instanceof SocketTimeoutException ) {
238
+ //ignore
239
+ } else {
240
+ throw e ;
241
+ }
242
+ }
243
+ Thread .sleep (1000 );
244
+ }
245
+ }
246
+
247
+ long processingFinished = System .currentTimeMillis ();
248
+ System .out .println ("Processed " + NUMBER_OF_USERS_TO_UPLOAD + " users in " + (processingFinished - processingStarted ) / 1000
249
+ + " seconds ( or " + (processingFinished - processingStarted ) / 60000 + " minutes)" );
250
+
251
+ // after processing finished, make sure every user got processed correctly
252
+ {
253
+ int failedImportedUsersNumber = loadBulkImportUsersCountWithStatus (main , BulkImportStorage .BULK_IMPORT_USER_STATUS .FAILED ).get ("count" ).getAsInt ();
254
+ int usersInCore = loadUsersCount (main ).get ("count" ).getAsInt ();
255
+ assertEquals (NUMBER_OF_USERS_TO_UPLOAD , usersInCore + failedImportedUsersNumber );
256
+ assertEquals (NUMBER_OF_USERS_TO_UPLOAD , usersInCore );
257
+ }
258
+
259
+ }
260
+
261
+
148
262
@ Test
149
263
public void testBatchWithOneUser () throws Exception {
150
264
Main main = startCronProcess ("14" );
@@ -801,7 +915,7 @@ private static JsonObject uploadBulkImportUsersJson(Main main, JsonObject reques
801
915
802
916
@ NotNull
803
917
private Main startCronProcess (String parallelism ) throws IOException , InterruptedException , TenantOrAppNotFoundException {
804
- return startCronProcess (parallelism , 5 * 60 );
918
+ return startCronProcess (parallelism , 5 * 60 );
805
919
}
806
920
807
921
@@ -814,15 +928,14 @@ private Main startCronProcess(String parallelism, int intervalInSeconds) throws
814
928
//Utils.setValueInConfig("bulk_migration_batch_size", "1000");
815
929
Utils .setValueInConfig ("log_level" , "DEBUG" );
816
930
817
- TestingProcessManager .TestingProcess process = TestingProcessManager .start (args , false );
931
+ TestingProcessManager .TestingProcess process = TestingProcessManager .start (args , true );
818
932
Main main = process .getProcess ();
819
933
setFeatureFlags (main , new EE_FEATURES [] {
820
934
EE_FEATURES .ACCOUNT_LINKING , EE_FEATURES .MULTI_TENANCY , EE_FEATURES .MFA });
821
935
// We are setting a non-zero initial wait for tests to avoid race condition with the beforeTest process that deletes data in the storage layer
822
936
CronTaskTest .getInstance (main ).setInitialWaitTimeInSeconds (ProcessBulkImportUsers .RESOURCE_KEY , 5 );
823
937
CronTaskTest .getInstance (main ).setIntervalInSeconds (ProcessBulkImportUsers .RESOURCE_KEY , intervalInSeconds );
824
938
825
- process .startProcess ();
826
939
assertNotNull (process .checkOrWaitForEvent (ProcessState .PROCESS_STATE .STARTED ));
827
940
828
941
Cronjobs .addCronjob (main , (ProcessBulkImportUsers ) main .getResourceDistributor ().getResource (new TenantIdentifier (null , null , null ), ProcessBulkImportUsers .RESOURCE_KEY ));
0 commit comments