Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds Exception handling to handle ALREADY EXISTS error #2788

Merged
merged 12 commits into from Jul 24, 2023
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -60,13 +60,13 @@ implementation 'com.google.cloud:google-cloud-bigquery'
If you are using Gradle without BOM, add this to your dependencies:

```Groovy
implementation 'com.google.cloud:google-cloud-bigquery:2.29.0'
implementation 'com.google.cloud:google-cloud-bigquery:2.30.0'
```

If you are using SBT, add this to your dependencies:

```Scala
libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.29.0"
libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.30.0"
```
<!-- {x-version-update-end} -->

Expand Down Expand Up @@ -351,7 +351,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-bigquery/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-bigquery.svg
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.29.0
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.30.0
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
Expand Down
Expand Up @@ -55,7 +55,11 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.threeten.bp.Instant;
import org.threeten.bp.temporal.ChronoUnit;

final class BigQueryImpl extends BaseService<BigQueryOptions> implements BigQuery {

Expand Down Expand Up @@ -422,15 +426,37 @@ public com.google.api.services.bigquery.model.Job call() {
}

if (!idRandom) {
if (createException instanceof BigQueryException && createException.getCause() != null) {

/*GoogleJsonResponseException createExceptionCause =
(GoogleJsonResponseException) createException.getCause();*/

Pattern pattern = Pattern.compile(".*Already.*Exists:.*Job.*", Pattern.CASE_INSENSITIVE);
Neenu1995 marked this conversation as resolved.
Show resolved Hide resolved
Matcher matcher = pattern.matcher(createException.getCause().getMessage());

if (matcher.find()) {
// If the Job ALREADY EXISTS, retrieve it.
Job job = this.getJob(jobInfo.getJobId());

long jobCreationTime = job.getStatistics().getCreationTime();
long endTime = System.currentTimeMillis();
long startTime = Instant.ofEpochMilli(endTime).minus(1, ChronoUnit.DAYS).toEpochMilli();
Neenu1995 marked this conversation as resolved.
Show resolved Hide resolved

// Only return the job if it has been created in the past 24 hours.
// This is assuming any job older than 24 hours is a valid duplicate JobID
// and not a false positive like b/290419183
if (jobCreationTime >= startTime && jobCreationTime <= endTime) {
return job;
}
}
}
throw createException;
}

// If create RPC fails, it's still possible that the job has been successfully
// created,
// and get might work.
// created, and get might work.
// We can only do this if we randomly generated the ID. Otherwise we might
// mistakenly
// fetch a job created by someone else.
// mistakenly fetch a job created by someone else.
Job job;
try {
job = getJob(finalJobId[0]);
Expand Down
Expand Up @@ -83,6 +83,7 @@
import com.google.cloud.bigquery.InsertAllRequest.RowToInsert;
import com.google.cloud.bigquery.InsertAllResponse;
import com.google.cloud.bigquery.Job;
import com.google.cloud.bigquery.JobConfiguration;
import com.google.cloud.bigquery.JobId;
import com.google.cloud.bigquery.JobInfo;
import com.google.cloud.bigquery.JobStatistics;
Expand Down Expand Up @@ -6076,4 +6077,29 @@ public void testForeignKeysUpdate() {
bigquery.delete(tableIdPk2);
}
}

@Test
public void testAlreadyExistJobExceptionHandling() throws InterruptedException {
String query =
"SELECT TimestampField, StringField, BooleanField FROM "
+ DATASET
+ "."
+ TABLE_ID.getTable();
JobId jobId = JobId.newBuilder().setRandomJob().build();

JobConfiguration queryJobConfiguration = QueryJobConfiguration.newBuilder(query).build();
// Creating the job with the explicit jobID
bigquery.create(JobInfo.of(jobId, queryJobConfiguration));
// Calling the query method with the job that has already been created.
// This should throw ALREADY_EXISTS error without the exception handling added
// or if the job is older than 24 hours.
try {
bigquery.query(QueryJobConfiguration.newBuilder(query).build(), jobId);
// Test succeeds if Exception is not thrown and code flow reaches this statement.
assertTrue(true);
} catch (BigQueryException ex) {
// test fails if an exception is thrown
assertTrue(false);
Neenu1995 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}