47
47
import java .util .concurrent .CountDownLatch ;
48
48
import java .util .concurrent .ExecutorService ;
49
49
import java .util .concurrent .Executors ;
50
+ import java .util .concurrent .TimeUnit ;
50
51
51
52
public class Main {
52
53
private final ExecutorService executorService ;
@@ -59,7 +60,7 @@ public class Main {
59
60
60
61
public Main () {
61
62
executorService = Executors .newFixedThreadPool (100 );
62
- // The SDK uses netty library for doing async IO operations, and the operations are performed the netty io threads.
63
+ // The SDK uses netty library for doing async IO operations. The IO operations are performed on the netty io threads.
63
64
// The number of IO netty threads are limited; it is the same as the number of CPU cores.
64
65
65
66
// The app should avoid doing anything which takes a lot of time from IO netty thread.
@@ -70,12 +71,11 @@ public Main() {
70
71
// * deadlock
71
72
72
73
// The app code will receive the data from Azure Cosmos DB on the netty IO thread.
73
- // The app should ensure the user's blocking call or computationally/IO heavy work after receiving data
74
- // from Azure Cosmos DB is performed on a custom thread managed by the user (not the SDK netty IO threads ).
74
+ // The app should ensure the user's computationally/IO heavy work after receiving data
75
+ // from Azure Cosmos DB is performed on a custom thread managed by the user (not on the SDK netty IO thread ).
75
76
//
76
- // If you are doing blocking calls or heavy work, provide your own scheduler to switch thread.
77
- // for example you can do this:
78
- // client.createDocument(.).observeOn(userCustomScheduler).toBlocking().single();
77
+ // If you are doing heavy work after receiving the result from the SDK,
78
+ // you should provide your own scheduler to switch thread.
79
79
80
80
// the following scheduler is used for switching from netty thread to user app thread.
81
81
scheduler = Schedulers .from (executorService );
@@ -92,7 +92,6 @@ public void close() {
92
92
* @param args command line args.
93
93
*/
94
94
public static void main (String [] args ) {
95
-
96
95
Main p = new Main ();
97
96
98
97
try {
@@ -196,7 +195,7 @@ private void createDatabaseIfNotExists() throws Exception {
196
195
// wait for completion,
197
196
// as waiting for completion is a blocking call try to
198
197
// provide your own scheduler to avoid stealing netty io threads.
199
- databaseExistenceObs .toCompletable ().observeOn ( scheduler ). await ();
198
+ databaseExistenceObs .toCompletable ().await ();
200
199
201
200
System .out .println ("Checking database " + databaseName + " completed!\n " );
202
201
}
@@ -229,7 +228,7 @@ private void createDocumentCollectionIfNotExists() throws Exception {
229
228
System .out .println ("Collection " + collectionName + "already exists" );
230
229
return Observable .empty ();
231
230
}
232
- }).toCompletable ().observeOn ( scheduler ). await ();
231
+ }).toCompletable ().await ();
233
232
234
233
System .out .println ("Checking collection " + collectionName + " completed!\n " );
235
234
}
@@ -268,7 +267,6 @@ private void createFamiliesAsyncAndRegisterListener(List<Family> families, Count
268
267
}
269
268
270
269
private void createFamiliesAndWaitForCompletion (List <Family > families ) throws Exception {
271
-
272
270
String collectionLink = String .format ("/dbs/%s/colls/%s" , databaseName , collectionName );
273
271
274
272
List <Observable <ResourceResponse <Document >>> createDocumentsOBs = new ArrayList <>();
@@ -280,6 +278,13 @@ private void createFamiliesAndWaitForCompletion(List<Family> families) throws Ex
280
278
281
279
Double totalRequestCharge = Observable .merge (createDocumentsOBs )
282
280
.map (ResourceResponse ::getRequestCharge )
281
+ .observeOn (scheduler ) // the scheduler will be used for the following work
282
+ .map (charge -> {
283
+ // as we don't want to run heavyWork() on netty IO thread, we provide the custom scheduler
284
+ // for switching from netty IO thread to user thread.
285
+ heavyWork ();
286
+ return charge ;
287
+ })
283
288
.reduce ((sum , value ) -> sum + value )
284
289
.toBlocking ().single ();
285
290
@@ -288,6 +293,17 @@ private void createFamiliesAndWaitForCompletion(List<Family> families) throws Ex
288
293
totalRequestCharge ));
289
294
}
290
295
296
+ private void heavyWork () {
297
+ // I may do a lot of IO work: e.g., writing to log files
298
+ // a lot of computational work
299
+ // or may do Thread.sleep()
300
+
301
+ try {
302
+ TimeUnit .SECONDS .sleep (2 );
303
+ } catch (Exception e ) {
304
+ }
305
+ }
306
+
291
307
private void executeSimpleQueryAsyncAndRegisterListenerForResult (CountDownLatch completionLatch ) {
292
308
// Set some common query options
293
309
FeedOptions queryOptions = new FeedOptions ();
@@ -299,22 +315,28 @@ private void executeSimpleQueryAsyncAndRegisterListenerForResult(CountDownLatch
299
315
client .queryDocuments (collectionLink ,
300
316
"SELECT * FROM Family WHERE Family.lastName = 'Andersen'" , queryOptions );
301
317
302
- queryObservable .subscribe (
303
- queryResultPage -> {
304
- System .out .println ("Got a page of query result with " +
305
- queryResultPage .getResults ().size () + " document(s)"
306
- + " and request charge of " + queryResultPage .getRequestCharge ());
307
- },
308
- // terminal error signal
309
- e -> {
310
- e .printStackTrace ();
311
- completionLatch .countDown ();
312
- },
313
-
314
- // terminal completion signal
315
- () -> {
316
- completionLatch .countDown ();
317
- });
318
+ queryObservable
319
+ .observeOn (scheduler )
320
+ .subscribe (
321
+ queryResultPage -> {
322
+ // we want to make sure heavyWork() doesn't block any of netty IO threads
323
+ // so we use observeOn(scheduler) to switch from the netty thread to user's thread.
324
+ heavyWork ();
325
+
326
+ System .out .println ("Got a page of query result with " +
327
+ queryResultPage .getResults ().size () + " document(s)"
328
+ + " and request charge of " + queryResultPage .getRequestCharge ());
329
+ },
330
+ // terminal error signal
331
+ e -> {
332
+ e .printStackTrace ();
333
+ completionLatch .countDown ();
334
+ },
335
+
336
+ // terminal completion signal
337
+ () -> {
338
+ completionLatch .countDown ();
339
+ });
318
340
}
319
341
320
342
private void writeToConsoleAndPromptToContinue (String text ) throws IOException {
0 commit comments