Skip to content

Commit 8e055f4

Browse files
committed
more dmsdk logging
1 parent bb2b16d commit 8e055f4

File tree

2 files changed

+134
-7
lines changed

2 files changed

+134
-7
lines changed

src/main/java/com/marklogic/client/datamovement/package-info.java

Lines changed: 116 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,20 @@
6666
* .withBatchSize(1000)
6767
* .withThreadCount(20)
6868
.withConsistentSnapshot()
69-
* .onUrisReady(batch -> {
69+
* .onUrisReady(batch -> {
7070
* for ( String uri : batch.getItems() ) {
7171
* if ( uri.endsWith(".txt") ) {
7272
* client.newDocumentManager().delete(uri);
7373
* }
7474
* }
7575
* })
76-
* .onQueryFailure(queryBatchException -> queryBatchException.printStackTrace());
76+
* .onQueryFailure(queryBatchException -> queryBatchException.printStackTrace());
7777
* JobTicket ticket = dataMovementManager.startJob(qhb);
7878
* qhb.awaitCompletion();
7979
* dataMovementManager.stopJob(ticket);
8080
* ```
8181
*
8282
*
83-
*
84-
*
85-
*
8683
* # Using WriteBatcher
8784
*
8885
* When you need to write a very large volume of documents and
@@ -95,10 +92,10 @@
9592
* WriteBatcher whb = dataMovementManager.newWriteBatcher()
9693
* .withBatchSize(100)
9794
* .withThreadCount(20)
98-
* .onBatchSuccess(batch -> {
95+
* .onBatchSuccess(batch -> {
9996
* logger.debug("batch # {}, so far: {}", batch.getJobBatchNumber(), batch.getJobResultsSoFar());
10097
* })
101-
* .onBatchFailure((batch,throwable) -> throwable.printStackTrace() );
98+
* .onBatchFailure((batch,throwable) -> throwable.printStackTrace() );
10299
* JobTicket ticket = dataMovementManager.startJob(whb);
103100
* // the add or addAs methods could be called in separate threads on the
104101
* // single whb instance
@@ -109,6 +106,118 @@
109106
* dataMovementManager.stopJob(ticket);
110107
* ```
111108
* [mlcp]: https://developer.marklogic.com/products/mlcp
109+
*
110+
*
111+
* <a name="lsnrs"></a>
112+
* # Writing Custom Listeners
113+
*
114+
* As demonstrated above, listeners should be added to each instance of
115+
* QueryBatcher or WriteBatcher. Ad-hoc listeners can be written as Java 8
116+
* lambda expressions. More sophisticated custom listeners can implement the
117+
* appropriate listener interface or extend one of the [provided listeners
118+
* listed above](#provided).
119+
*
120+
* QueryBatchListener (onUrisReady) instances are necessary to do something
121+
* with the uris fetched by QueryBatcher. What a custom QueryBatchListener
122+
* does is completely up to it, but any operation which operates on uris
123+
* offered by any part of the Java Client API could be used, as could any read
124+
* or write to an external system. QueryFailureListener (onQueryFailure)
125+
* instances handle any exceptions encoutnered fetching the uris.
126+
* WriteBatchListener (onBatchSuccess) instances handle any custom tracking
127+
* requirements during a WriteBatcher job. WriteFailureListener
128+
* (onBatchFailure) instances handle any exceptions encountered writing the
129+
* batches formed from docs send to the WriteBatcher instance. See the
130+
* javadocs for each [provided listener](#provided) for an explantion of the
131+
* various listeners that can be registered for it to call. See javadocs, the
132+
* [Java Application Developer's Guide][], [source code for provided
133+
* listeners][], [cookbook examples][], and [unit tests][] for more examples of
134+
* listener implementation ideas.
135+
*
136+
* [Java Application Developer's Guide]: http://docs.marklogic.com/guide/java
137+
* [source code for provided listeners]: https://github.com/marklogic/java-client-api
138+
* [cookbook examples]: https://github.com/marklogic/java-client-api/tree/develop/src/main/java/com/marklogic/client/example/cookbook/datamovement
139+
* [unit tests]: https://github.com/marklogic/java-client-api/tree/develop/src/test/java/com/marklogic/client/test/datamovement
140+
*
141+
* # Listners Must Be Thread-Safe
142+
*
143+
* Since listeners are called asynchronously by all threads in the pool inside
144+
* the QueryBatcher or WriteBatcher instance, they must only perform
145+
* thread-safe operations. For example, accumulating to a collection should
146+
* only be done with collections wrapped as
147+
* {@link java.util.Collections#synchronizedCollection synchronized Collections}
148+
* rather than directly using un-synchronized collections such as HashMap or
149+
* ArrayList which are not thread-safe. Similarly, accumulating to a string
150+
* should use StringBuffer insted of StringBuilder since StringBuffer is
151+
* synchronized (and thus thread-safe). We also recommend {@link
152+
* java.util.concurrent.atomic java.util.concurrent.atomic classes}.
153+
*
154+
* Listeners should handle their own exceptions as described below in
155+
* [Handling Exceptions in Listeners](#errs).
156+
*
157+
*
158+
* <a name="errs"></a>
159+
* # Handling Exceptions in Listeners
160+
*
161+
* Since listeners are called asynchrounously, external exception handling
162+
* cannot wrap the call in a try-catch block. Instead, a listener can and
163+
* should handle its own exceptions by wrapping the calls in its body in a
164+
* try-catch block. When any listener does not handle its own exceptions and
165+
* throws any exception (Throwable), the exception is logged at error level
166+
* with a call like:
167+
*
168+
* logger.error("Exception thrown by an onBatchSuccess listener", throwable);
169+
*
170+
* This achieves logging of exceptions without allowing them to prevent the job
171+
* from continuing.
172+
*
173+
* A QueryFailureListener or WriteFailureListener will not be notified of
174+
* exceptions thrown by other listeners. Instead, these failure listeners are
175+
* notified exclusively of exceptions in the operation of QueryBatcher or
176+
* WriteBatcher.
177+
*
178+
* If you wish a custom QueryBatchListener or WriteBatchListener to trap its
179+
* own exceptions and pass them along to callbacks registered with it for
180+
* exception handling, it can of course do that in a custom way. Examples of
181+
* this pattern can be seen in the interface of
182+
* {@link com.marklogic.client.datamovement.ApplyTransformListener}.
183+
*
184+
* # Pre-installed Listeners
185+
*
186+
* Every time you create a new QueryBatcher or WriteBatcher it comes with some
187+
* pre-installed listeners such as
188+
* {@link com.marklogic.client.datamovement.HostAvailabilityListener} and a
189+
* listener to track counts for JobReport. If you wish to remove these
190+
* listeners and their associated functionality call one of the following:
191+
* {@link com.marklogic.client.datamovement.QueryBatcher#setUrisReadyListeners
192+
* setUrisReadyListeners}, {@link
193+
* com.marklogic.client.datamovement.QueryBatcher#setQueryFailureListeners
194+
* setQueryFailureListeners}, {@link
195+
* com.marklogic.client.datamovement.WriteBatcher#setBatchSuccessListeners
196+
* setBatchSuccessListeners}, or {@link
197+
* com.marklogic.client.datamovement.WriteBatcher#setBatchFailureListeners
198+
* setBatchFailureListeners}. Obviously, removing the functionality of
199+
* HostAvailabilityListener means it won't do its job of handling black-listing
200+
* hosts or retrying batches that occur when a host is unavailable. And
201+
* removing the functionality of the listeners that track counts for JobReport
202+
* means JobReport should no longer be used. If you would just like to change
203+
* the settings on HostAvailabilityListener, you can do something like the
204+
* following:
205+
*
206+
* for (WriteFailureListener listener : batcher.getBatchFailureListeners()) {
207+
* if ( listener instanceof HostAvailabilityListener ) {
208+
* ((HostAvailabilityListener) listener)
209+
* .withSuspendTimeForHostUnavailable(Duration.ofMinutes(60))
210+
* .withMinHosts(2);
211+
* }
212+
* }
213+
*
214+
*
215+
* <h2>Enable Logging</h2>
216+
*
217+
* We have made efforts to provide helpful logging as you use QueryBatcher and
218+
* WriteBatcher. Please make sure to enable your slf4j-compliant [logging
219+
* framework](../../../../overview-summary.html#logging).
220+
*
112221
*/
113222
/*
114223
* Copyright 2015-2016 MarkLogic Corporation

src/main/javadoc/overview.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,5 +321,23 @@ <h2>Registering New IO Representations for Shortcut Methods</h2>
321321

322322
Product product = docMgr.readAs(docId, Product.class);
323323
</pre>
324+
325+
<a name="logging"></a>
326+
<h2>Enabling Logging</h2>
327+
<p>
328+
We use <a href="http://www.slf4j.org/manual.html">slf4j</a> for logging.
329+
This means you can choose any slf4j-compliant logging framework such as
330+
Logback, AVSL, JDK logging, Log4j, or Simple. If you don't know which to
331+
choose, we recommend Logback since it is a native implementation and the
332+
easiest to configure. Please follow the instructions on the slf4j website to
333+
configure your logging framework. It should take no more than 15 minutes.
334+
335+
Once your logging framework is configured with slf4j, you should be able to
336+
see and manage logging from the Java-client API. This is especially
337+
important for long-running QueryBatcher and WriteBatcher jobs.
338+
</p>
339+
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
340+
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
341+
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
324342
</body>
325343
</html>

0 commit comments

Comments
 (0)