diff --git a/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProvider.java b/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProvider.java index 5d9a771c7..66392af08 100644 --- a/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProvider.java +++ b/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProvider.java @@ -1,12 +1,12 @@ package net.javacrumbs.shedlock.provider.spanner; +import static java.util.Objects.requireNonNull; + import com.google.cloud.spanner.DatabaseClient; import net.javacrumbs.shedlock.support.StorageBasedLockProvider; import net.javacrumbs.shedlock.support.Utils; import net.javacrumbs.shedlock.support.annotation.NonNull; -import static java.util.Objects.requireNonNull; - /** * A lock provider for Google Cloud Spanner. * This provider uses Spanner as the backend storage for the locks. @@ -19,10 +19,8 @@ public class SpannerLockProvider extends StorageBasedLockProvider { * @param databaseClient the client for interacting with Google Cloud Spanner. */ public SpannerLockProvider(@NonNull DatabaseClient databaseClient) { - this(new SpannerStorageAccessor(Configuration.builder() - .withDatabaseClient(databaseClient) - .build() - )); + this(new SpannerStorageAccessor( + Configuration.builder().withDatabaseClient(databaseClient).build())); } /** @@ -100,15 +98,14 @@ public static final class Builder { // Default table configuration if not specified by the user of the builder. private TableConfiguration tableConfiguration = TableConfiguration.builder() - .withTableName("shedlock") - .withLockName("name") - .withLockedBy("locked_by") - .withLockedAt("locked_at") - .withLockUntil("lock_until") - .build(); - - private Builder() { - } + .withTableName("shedlock") + .withLockName("name") + .withLockedBy("locked_by") + .withLockedAt("locked_at") + .withLockUntil("lock_until") + .build(); + + private Builder() {} public Builder withDatabaseClient(DatabaseClient databaseClient) { this.databaseClient = databaseClient; @@ -186,7 +183,6 @@ public String getLockedBy() { return lockedBy; } - /** * Builder for creating {@code TableConfiguration} instances. */ @@ -197,8 +193,7 @@ public static final class Builder { private String lockedAt; private String lockedBy; - private Builder() { - } + private Builder() {} public Builder withTableName(String tableName) { this.tableName = tableName; @@ -233,7 +228,6 @@ public Builder withLockedBy(String lockedByColumn) { public TableConfiguration build() { return new TableConfiguration(this); } - } } } diff --git a/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerStorageAccessor.java b/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerStorageAccessor.java index c3a16727a..50a9798e7 100644 --- a/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerStorageAccessor.java +++ b/providers/spanner/shedlock-provider-spanner/src/main/java/net/javacrumbs/shedlock/provider/spanner/SpannerStorageAccessor.java @@ -8,13 +8,12 @@ import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.Struct; import com.google.cloud.spanner.TransactionContext; -import net.javacrumbs.shedlock.core.LockConfiguration; -import net.javacrumbs.shedlock.support.AbstractStorageAccessor; -import net.javacrumbs.shedlock.support.annotation.NonNull; - import java.time.Instant; import java.util.List; import java.util.Optional; +import net.javacrumbs.shedlock.core.LockConfiguration; +import net.javacrumbs.shedlock.support.AbstractStorageAccessor; +import net.javacrumbs.shedlock.support.annotation.NonNull; /** * Accessor for managing lock records within a Google Spanner database. @@ -54,22 +53,24 @@ public SpannerStorageAccessor(SpannerLockProvider.Configuration configuration) { */ @Override public boolean insertRecord(@NonNull LockConfiguration lockConfiguration) { - return Boolean.TRUE.equals(databaseClient.readWriteTransaction().run(transaction -> - findLock(transaction, lockConfiguration.getName()) + return Boolean.TRUE.equals(databaseClient.readWriteTransaction().run(transaction -> findLock( + transaction, lockConfiguration.getName()) .map(lock -> false) // Lock already exists, so we return false. .orElseGet(() -> { transaction.buffer(Mutation.newInsertBuilder(table) - .set(name).to(lockConfiguration.getName()) - .set(lockUntil).to(toTimestamp(lockConfiguration.getLockAtMostUntil())) - .set(lockedAt).to(Timestamp.now()) - .set(lockedBy).to(hostname) - .build()); + .set(name) + .to(lockConfiguration.getName()) + .set(lockUntil) + .to(toTimestamp(lockConfiguration.getLockAtMostUntil())) + .set(lockedAt) + .to(Timestamp.now()) + .set(lockedBy) + .to(hostname) + .build()); return true; - }) - )); + }))); } - /** * Attempts to update an existing lock record in the Spanner table. * @@ -78,19 +79,23 @@ public boolean insertRecord(@NonNull LockConfiguration lockConfiguration) { */ @Override public boolean updateRecord(@NonNull LockConfiguration lockConfiguration) { - return Boolean.TRUE.equals(databaseClient.readWriteTransaction().run(transaction -> - findLock(transaction, lockConfiguration.getName()) + return Boolean.TRUE.equals(databaseClient.readWriteTransaction().run(transaction -> findLock( + transaction, lockConfiguration.getName()) .filter(lock -> lock.getLockedUntil().compareTo(Timestamp.now()) <= 0) .map(lock -> { transaction.buffer(Mutation.newUpdateBuilder(table) - .set(name).to(lockConfiguration.getName()) - .set(lockUntil).to(toTimestamp(lockConfiguration.getLockAtMostUntil())) - .set(lockedAt).to(Timestamp.now()) - .set(lockedBy).to(hostname) - .build()); + .set(name) + .to(lockConfiguration.getName()) + .set(lockUntil) + .to(toTimestamp(lockConfiguration.getLockAtMostUntil())) + .set(lockedAt) + .to(Timestamp.now()) + .set(lockedBy) + .to(hostname) + .build()); return true; - }).orElse(false) - )); + }) + .orElse(false))); } /** @@ -101,18 +106,20 @@ public boolean updateRecord(@NonNull LockConfiguration lockConfiguration) { */ @Override public boolean extend(@NonNull LockConfiguration lockConfiguration) { - return Boolean.TRUE.equals(databaseClient.readWriteTransaction().run(transaction -> - findLock(transaction, lockConfiguration.getName()) + return Boolean.TRUE.equals(databaseClient.readWriteTransaction().run(transaction -> findLock( + transaction, lockConfiguration.getName()) .filter(lock -> hostname.equals(lock.getLockedBy())) .filter(lock -> lock.getLockedUntil().compareTo(Timestamp.now()) > 0) .map(lock -> { - transaction.buffer( - Mutation.newUpdateBuilder(table) - .set(name).to(lockConfiguration.getName()) - .set(lockUntil).to(toTimestamp(lockConfiguration.getLockAtMostUntil())) + transaction.buffer(Mutation.newUpdateBuilder(table) + .set(name) + .to(lockConfiguration.getName()) + .set(lockUntil) + .to(toTimestamp(lockConfiguration.getLockAtMostUntil())) .build()); return true; - }).orElse(false))); + }) + .orElse(false))); } /** @@ -124,12 +131,12 @@ public boolean extend(@NonNull LockConfiguration lockConfiguration) { public void unlock(@NonNull LockConfiguration lockConfiguration) { databaseClient.readWriteTransaction().run(transaction -> { findLock(transaction, lockConfiguration.getName()) - .filter(lock -> hostname.equals(lock.getLockedBy())) - .ifPresent(lock -> - transaction.buffer( - Mutation.newUpdateBuilder(table) - .set(name).to(lockConfiguration.getName()) - .set(lockUntil).to(toTimestamp(lockConfiguration.getUnlockTime())) + .filter(lock -> hostname.equals(lock.getLockedBy())) + .ifPresent(lock -> transaction.buffer(Mutation.newUpdateBuilder(table) + .set(name) + .to(lockConfiguration.getName()) + .set(lockUntil) + .to(toTimestamp(lockConfiguration.getUnlockTime())) .build())); return null; // need a return to commit the transaction }); @@ -143,20 +150,21 @@ public void unlock(@NonNull LockConfiguration lockConfiguration) { * @return An {@code Optional} containing the lock if found, otherwise empty. */ protected Optional findLock(TransactionContext transaction, String lockName) { - return Optional.ofNullable(transaction.readRow( - table, - Key.of(lockName), - List.of(name, lockUntil, lockedBy, lockedAt))) - .map(Lock::new); + return Optional.ofNullable( + transaction.readRow(table, Key.of(lockName), List.of(name, lockUntil, lockedBy, lockedAt))) + .map(Lock::new); } protected Optional nonTransactionFindLock(String lockName) { - return Optional.ofNullable(databaseClient.singleUse().executeQuery(Statement.newBuilder("SELECT * FROM " + table + " WHERE " + name + " = @name") - .bind(name).to(lockName) - .build())) - .filter(ResultSet::next) - .map(ResultSet::getCurrentRowAsStruct) - .map(Lock::new); + return Optional.ofNullable(databaseClient + .singleUse() + .executeQuery(Statement.newBuilder("SELECT * FROM " + table + " WHERE " + name + " = @name") + .bind(name) + .to(lockName) + .build())) + .filter(ResultSet::next) + .map(ResultSet::getCurrentRowAsStruct) + .map(Lock::new); } /** @@ -206,5 +214,4 @@ protected Timestamp getLockedUntil() { return lockedUntil; } } - } diff --git a/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/AbstractSpannerStorageBasedLockProviderIntegrationTest.java b/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/AbstractSpannerStorageBasedLockProviderIntegrationTest.java index a261b8036..c26024305 100644 --- a/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/AbstractSpannerStorageBasedLockProviderIntegrationTest.java +++ b/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/AbstractSpannerStorageBasedLockProviderIntegrationTest.java @@ -12,6 +12,8 @@ import com.google.cloud.spanner.InstanceInfo; import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerOptions; +import java.util.List; +import java.util.concurrent.ExecutionException; import net.javacrumbs.shedlock.test.support.AbstractStorageBasedLockProviderIntegrationTest; import org.junit.jupiter.api.BeforeAll; import org.testcontainers.containers.SpannerEmulatorContainer; @@ -19,11 +21,9 @@ import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; -import java.util.List; -import java.util.concurrent.ExecutionException; - @Testcontainers -public abstract class AbstractSpannerStorageBasedLockProviderIntegrationTest extends AbstractStorageBasedLockProviderIntegrationTest { +public abstract class AbstractSpannerStorageBasedLockProviderIntegrationTest + extends AbstractStorageBasedLockProviderIntegrationTest { private static final String SPANNER_EMULATOR_IMAGE = "gcr.io/cloud-spanner-emulator/emulator:latest"; private static final String PROJECT_NAME = "test-project"; @@ -34,8 +34,7 @@ public abstract class AbstractSpannerStorageBasedLockProviderIntegrationTest ext @Container public static final SpannerEmulatorContainer emulator = - new SpannerEmulatorContainer(DockerImageName.parse(SPANNER_EMULATOR_IMAGE)); - + new SpannerEmulatorContainer(DockerImageName.parse(SPANNER_EMULATOR_IMAGE)); @BeforeAll public static void setUpSpanner() { @@ -50,12 +49,11 @@ static DatabaseClient getDatabaseClient() { } private static Spanner createSpannerService() { - SpannerOptions options = SpannerOptions - .newBuilder() - .setEmulatorHost(emulator.getEmulatorGrpcEndpoint()) - .setCredentials(NoCredentials.getInstance()) - .setProjectId(PROJECT_NAME) - .build(); + SpannerOptions options = SpannerOptions.newBuilder() + .setEmulatorHost(emulator.getEmulatorGrpcEndpoint()) + .setCredentials(NoCredentials.getInstance()) + .setProjectId(PROJECT_NAME) + .build(); return options.getService(); } @@ -66,15 +64,12 @@ private static InstanceId createInstance(Spanner spanner) { InstanceAdminClient insAdminClient = spanner.getInstanceAdminClient(); try { Instance instance = insAdminClient - .createInstance( - InstanceInfo - .newBuilder(instanceId) - .setNodeCount(1) - .setDisplayName("Test instance") - .setInstanceConfigId(instanceConfig) - .build() - ) - .get(); + .createInstance(InstanceInfo.newBuilder(instanceId) + .setNodeCount(1) + .setDisplayName("Test instance") + .setInstanceConfigId(instanceConfig) + .build()) + .get(); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException("Failed creating Spanner instance.", e); } @@ -85,12 +80,8 @@ private static DatabaseId createDatabase(Spanner spanner) { DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient(); try { Database database = dbAdminClient - .createDatabase( - INSTANCE_NAME, - DATABASE_NAME, - List.of(getShedlockDdl()) - ) - .get(); + .createDatabase(INSTANCE_NAME, DATABASE_NAME, List.of(getShedlockDdl())) + .get(); return database.getId(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException("Failed creating Spanner database.", e); @@ -98,8 +89,7 @@ private static DatabaseId createDatabase(Spanner spanner) { } private static String getShedlockDdl() { - return - """ + return """ CREATE TABLE shedlock ( name STRING(64) NOT NULL, lock_until TIMESTAMP NOT NULL, @@ -108,5 +98,4 @@ locked_by STRING(255) NOT NULL ) PRIMARY KEY (name) """; } - } diff --git a/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProviderIntegrationTest.java b/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProviderIntegrationTest.java index 5a6a438cc..acbdc3705 100644 --- a/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProviderIntegrationTest.java +++ b/providers/spanner/shedlock-provider-spanner/src/test/java/net/javacrumbs/shedlock/provider/spanner/SpannerLockProviderIntegrationTest.java @@ -1,18 +1,17 @@ package net.javacrumbs.shedlock.provider.spanner; +import static org.assertj.core.api.Assertions.assertThat; + import com.google.cloud.Timestamp; import com.google.cloud.spanner.KeySet; import com.google.cloud.spanner.Mutation; +import java.time.Instant; +import java.util.List; import net.javacrumbs.shedlock.core.ClockProvider; import net.javacrumbs.shedlock.support.StorageBasedLockProvider; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import java.time.Instant; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - class SpannerLockProviderIntegrationTest extends AbstractSpannerStorageBasedLockProviderIntegrationTest { private static SpannerStorageAccessor accessor; @@ -20,8 +19,8 @@ class SpannerLockProviderIntegrationTest extends AbstractSpannerStorageBasedLock @BeforeAll static void setUp() { SpannerLockProvider.Configuration configuration = SpannerLockProvider.Configuration.builder() - .withDatabaseClient(getDatabaseClient()) - .build(); + .withDatabaseClient(getDatabaseClient()) + .build(); accessor = new SpannerStorageAccessor(configuration); } @@ -65,5 +64,4 @@ private void cleanLockTable() { private Instant toInstant(Timestamp timestamp) { return Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); } - }