@@ -27,6 +27,7 @@ public class SnowflakeCopyBatchInsert implements BatchInsert {
2727 protected static final String newLineString = "\n " ;
2828 protected static final String delimiterString = "\t " ;
2929 private final int maxUploadRetries ;
30+ private final int maxCopyRetries ;
3031
3132 private SnowflakeOutputConnection connection = null ;
3233 private TableIdentifier tableIdentifier = null ;
@@ -51,6 +52,7 @@ public SnowflakeCopyBatchInsert(
5152 int [] copyIntoCSVColumnNumbers ,
5253 boolean deleteStageFile ,
5354 int maxUploadRetries ,
55+ int maxCopyRetries ,
5456 boolean emptyFieldAsNull )
5557 throws IOException {
5658 this .index = 0 ;
@@ -63,6 +65,7 @@ public SnowflakeCopyBatchInsert(
6365 this .deleteStageFile = deleteStageFile ;
6466 this .uploadAndCopyFutures = new ArrayList ();
6567 this .maxUploadRetries = maxUploadRetries ;
68+ this .maxCopyRetries = maxCopyRetries ;
6669 this .emptyFieldAsNull = emptyFieldAsNull ;
6770 }
6871
@@ -270,7 +273,8 @@ public void flush() throws IOException, SQLException {
270273 Future <Void > uploadFuture = executorService .submit (uploadTask );
271274 uploadAndCopyFutures .add (uploadFuture );
272275
273- CopyTask copyTask = new CopyTask (uploadFuture , snowflakeStageFileName , emptyFieldAsNull );
276+ CopyTask copyTask =
277+ new CopyTask (uploadFuture , snowflakeStageFileName , emptyFieldAsNull , maxCopyRetries );
274278 uploadAndCopyFutures .add (executorService .submit (copyTask ));
275279
276280 fileCount ++;
@@ -404,40 +408,62 @@ private class CopyTask implements Callable<Void> {
404408 private final Future <Void > uploadFuture ;
405409 private final String snowflakeStageFileName ;
406410 private final boolean emptyFieldAsNull ;
411+ private final int maxCopyRetries ;
407412
408413 public CopyTask (
409- Future <Void > uploadFuture , String snowflakeStageFileName , boolean emptyFieldAsNull ) {
414+ Future <Void > uploadFuture ,
415+ String snowflakeStageFileName ,
416+ boolean emptyFieldAsNull ,
417+ int maxCopyRetries ) {
410418 this .uploadFuture = uploadFuture ;
411419 this .snowflakeStageFileName = snowflakeStageFileName ;
412420 this .emptyFieldAsNull = emptyFieldAsNull ;
421+ this .maxCopyRetries = maxCopyRetries ;
413422 }
414423
415424 public Void call () throws SQLException , InterruptedException , ExecutionException {
416425 try {
417426 uploadFuture .get ();
418427
419428 SnowflakeOutputConnection con = (SnowflakeOutputConnection ) connector .connect (true );
420- try {
421- logger .info ("Running COPY from file {}" , snowflakeStageFileName );
422-
423- long startTime = System .currentTimeMillis ();
424- con .runCopy (
425- tableIdentifier ,
426- stageIdentifier ,
427- snowflakeStageFileName ,
428- copyIntoTableColumnNames ,
429- copyIntoCSVColumnNumbers ,
430- delimiterString ,
431- emptyFieldAsNull );
432-
433- double seconds = (System .currentTimeMillis () - startTime ) / 1000.0 ;
434-
435- logger .info (
436- String .format (
437- "Loaded file %s (%.2f seconds for COPY)" , snowflakeStageFileName , seconds ));
438-
439- } finally {
440- con .close ();
429+ int retries = 0 ;
430+ while (true ) {
431+ try {
432+ logger .info ("Running COPY from file {}" , snowflakeStageFileName );
433+
434+ long startTime = System .currentTimeMillis ();
435+ con .runCopy (
436+ tableIdentifier ,
437+ stageIdentifier ,
438+ snowflakeStageFileName ,
439+ copyIntoTableColumnNames ,
440+ copyIntoCSVColumnNumbers ,
441+ delimiterString ,
442+ emptyFieldAsNull );
443+
444+ double seconds = (System .currentTimeMillis () - startTime ) / 1000.0 ;
445+
446+ logger .info (
447+ String .format (
448+ "Loaded file %s (%.2f seconds for COPY)" , snowflakeStageFileName , seconds ));
449+
450+ break ;
451+ } catch (SQLException e ) {
452+ if (!isRetryableForCopyTask (e )) {
453+ throw e ;
454+ }
455+
456+ retries ++;
457+ if (retries > this .maxCopyRetries ) {
458+ throw e ;
459+ }
460+ logger .warn (
461+ String .format (
462+ "Copy error %s file %s retries: %d" , e , snowflakeStageFileName , retries ));
463+ Thread .sleep (retries * retries * 1000 );
464+ } finally {
465+ con .close ();
466+ }
441467 }
442468 } finally {
443469 if (deleteStageFile ) {
@@ -447,5 +473,10 @@ public Void call() throws SQLException, InterruptedException, ExecutionException
447473
448474 return null ;
449475 }
476+
477+ private boolean isRetryableForCopyTask (SQLException e ) {
478+ String message = e .getMessage ();
479+ return message != null && message .contains ("JDBC driver encountered communication error" );
480+ }
450481 }
451482}
0 commit comments