diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtils.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtils.java index 3307eb5e..e2a66164 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtils.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtils.java @@ -44,7 +44,9 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; +import com.kingsrook.qqq.backend.core.utils.ObjectUtils; import com.kingsrook.qqq.backend.core.utils.SleepUtils; +import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.core.utils.memoization.Memoization; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; @@ -80,7 +82,10 @@ public class ProcessLockUtils } QSession qSession = QContext.getQSession(); - holder = qSession.getUser().getIdReference() + "-" + qSession.getUuid() + "-" + holder; + holder = ObjectUtils.tryAndRequireNonNullElse(() -> qSession.getUser().getIdReference(), "anonymous") + + "-" + + ObjectUtils.tryAndRequireNonNullElse(() -> qSession.getUuid(), "no-session") + + (StringUtils.hasContent(holder) ? ("-" + holder) : ""); Instant now = Instant.now(); ProcessLock processLock = new ProcessLock() @@ -240,9 +245,53 @@ public class ProcessLockUtils /******************************************************************************* ** *******************************************************************************/ - public static void release(ProcessLock processLock) throws QException + public static void releaseById(Integer id) { - DeleteOutput deleteOutput = new DeleteAction().execute(new DeleteInput(ProcessLock.TABLE_NAME).withPrimaryKey(processLock.getId())); + if(id == null) + { + LOG.debug("No id passed in to releaseById - returning with noop"); + return; + } + + ProcessLock processLock = null; + try + { + processLock = ProcessLockUtils.getById(id); + if(processLock == null) + { + LOG.info("Process lock not found in releaseById call", logPair("id", id)); + } + } + catch(QException e) + { + LOG.warn("Exception releasing processLock byId", e, logPair("id", id)); + } + + if(processLock != null) + { + release(processLock); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static void release(ProcessLock processLock) + { + try + { + DeleteOutput deleteOutput = new DeleteAction().execute(new DeleteInput(ProcessLock.TABLE_NAME).withPrimaryKey(processLock.getId())); + if(CollectionUtils.nullSafeHasContents(deleteOutput.getRecordsWithErrors())) + { + throw (new QException("Error deleting processLock record: " + deleteOutput.getRecordsWithErrors().get(0).getErrorsAsString())); + } + } + catch(QException e) + { + LOG.warn("Exception releasing processLock", e, logPair("processLockId", () -> processLock.getId())); + } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtilsTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtilsTest.java index b665fed0..5c17420c 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtilsTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/locks/ProcessLockUtilsTest.java @@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.session.QUser; import com.kingsrook.qqq.backend.core.utils.SleepUtils; import com.kingsrook.qqq.backend.core.utils.TestUtils; import org.junit.jupiter.api.BeforeEach; @@ -189,8 +190,56 @@ class ProcessLockUtilsTest extends BaseTest ProcessLockUtils.checkIn(processLock); ProcessLock freshLock = ProcessLockUtils.getById(processLock.getId()); + assertNotNull(freshLock); assertNotEquals(originalCheckIn, freshLock.getCheckInTimestamp()); assertNotEquals(originalExpiration, freshLock.getExpiresAtTimestamp()); } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testReleaseById() throws QException + { + //////////////////////////////////////////// + // assert no exceptions for these 2 cases // + //////////////////////////////////////////// + ProcessLockUtils.releaseById(null); + ProcessLockUtils.releaseById(1); + + ProcessLock processLock = ProcessLockUtils.create("1", "typeA", "me"); + ProcessLockUtils.releaseById(processLock.getId()); + assertNull(ProcessLockUtils.getById(processLock.getId())); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testHolders() throws QException + { + QContext.getQSession().setUser(new QUser().withIdReference("me")); + assertThat(ProcessLockUtils.create("1", "typeA", null).getHolder()) + .isEqualTo("me-" + QContext.getQSession().getUuid()); + + assertThat(ProcessLockUtils.create("2", "typeA", "foo").getHolder()) + .isEqualTo("me-" + QContext.getQSession().getUuid() + "-foo"); + + QContext.getQSession().setUser(null); + assertThat(ProcessLockUtils.create("3", "typeA", "bar").getHolder()) + .isEqualTo("anonymous-" + QContext.getQSession().getUuid() + "-bar"); + + QContext.getQSession().setUuid(null); + assertThat(ProcessLockUtils.create("4", "typeA", "baz").getHolder()) + .isEqualTo("anonymous-no-session-baz"); + + QContext.getQSession().setUuid(null); + assertThat(ProcessLockUtils.create("5", "typeA", "").getHolder()) + .isEqualTo("anonymous-no-session"); + } + } \ No newline at end of file