CE-938 Make session & user explicit fields, instead of packing into "holder"

This commit is contained in:
2024-05-21 11:35:00 -05:00
parent e6190b4fe2
commit 3e26ea94ee
4 changed files with 147 additions and 61 deletions

View File

@ -51,8 +51,14 @@ public class ProcessLock extends QRecordEntity
@QField(possibleValueSourceName = ProcessLockType.TABLE_NAME) @QField(possibleValueSourceName = ProcessLockType.TABLE_NAME)
private Integer processLockTypeId; private Integer processLockTypeId;
@QField(isRequired = true, maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR) @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR)
private String holder; private String userId;
@QField(label = "Session UUID", maxLength = 36, valueTooLongBehavior = ValueTooLongBehavior.ERROR)
private String sessionUUID;
@QField(maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR)
private String details;
@QField() @QField()
private Instant checkInTimestamp; private Instant checkInTimestamp;
@ -205,37 +211,6 @@ public class ProcessLock extends QRecordEntity
/*******************************************************************************
** Getter for holder
*******************************************************************************/
public String getHolder()
{
return (this.holder);
}
/*******************************************************************************
** Setter for holder
*******************************************************************************/
public void setHolder(String holder)
{
this.holder = holder;
}
/*******************************************************************************
** Fluent setter for holder
*******************************************************************************/
public ProcessLock withHolder(String holder)
{
this.holder = holder;
return (this);
}
/******************************************************************************* /*******************************************************************************
** Getter for checkInTimestamp ** Getter for checkInTimestamp
*******************************************************************************/ *******************************************************************************/
@ -327,4 +302,97 @@ public class ProcessLock extends QRecordEntity
return (this); return (this);
} }
/*******************************************************************************
** Getter for userId
*******************************************************************************/
public String getUserId()
{
return (this.userId);
}
/*******************************************************************************
** Setter for userId
*******************************************************************************/
public void setUserId(String userId)
{
this.userId = userId;
}
/*******************************************************************************
** Fluent setter for userId
*******************************************************************************/
public ProcessLock withUserId(String userId)
{
this.userId = userId;
return (this);
}
/*******************************************************************************
** Getter for sessionUUID
*******************************************************************************/
public String getSessionUUID()
{
return (this.sessionUUID);
}
/*******************************************************************************
** Setter for sessionUUID
*******************************************************************************/
public void setSessionUUID(String sessionUUID)
{
this.sessionUUID = sessionUUID;
}
/*******************************************************************************
** Fluent setter for sessionUUID
*******************************************************************************/
public ProcessLock withSessionUUID(String sessionUUID)
{
this.sessionUUID = sessionUUID;
return (this);
}
/*******************************************************************************
** Getter for details
*******************************************************************************/
public String getDetails()
{
return (this.details);
}
/*******************************************************************************
** Setter for details
*******************************************************************************/
public void setDetails(String details)
{
this.details = details;
}
/*******************************************************************************
** Fluent setter for details
*******************************************************************************/
public ProcessLock withDetails(String details)
{
this.details = details;
return (this);
}
} }

View File

@ -63,7 +63,7 @@ public class ProcessLockMetaDataProducer implements MetaDataProducerInterface<Me
.withRecordLabelFormat("%s %s") .withRecordLabelFormat("%s %s")
.withRecordLabelFields("processLockTypeId", "key") .withRecordLabelFields("processLockTypeId", "key")
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "processLockTypeId", "key"))) .withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "processLockTypeId", "key")))
.withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("holder", "checkInTimestamp", "expiresAtTimestamp"))) .withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("userId", "sessionUUID", "message", "checkInTimestamp", "expiresAtTimestamp")))
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate"))) .withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")))
); );

View File

@ -46,7 +46,6 @@ import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.ObjectUtils; import com.kingsrook.qqq.backend.core.utils.ObjectUtils;
import com.kingsrook.qqq.backend.core.utils.SleepUtils; 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.ValueUtils;
import com.kingsrook.qqq.backend.core.utils.memoization.Memoization; import com.kingsrook.qqq.backend.core.utils.memoization.Memoization;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -73,7 +72,7 @@ public class ProcessLockUtils
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public static ProcessLock create(String key, String typeName, String holder) throws UnableToObtainProcessLockException, QException public static ProcessLock create(String key, String typeName, String details) throws UnableToObtainProcessLockException, QException
{ {
ProcessLockType lockType = getProcessLockTypeByName(typeName); ProcessLockType lockType = getProcessLockTypeByName(typeName);
if(lockType == null) if(lockType == null)
@ -82,16 +81,14 @@ public class ProcessLockUtils
} }
QSession qSession = QContext.getQSession(); QSession qSession = QContext.getQSession();
holder = ObjectUtils.tryAndRequireNonNullElse(() -> qSession.getUser().getIdReference(), "anonymous")
+ "-"
+ ObjectUtils.tryAndRequireNonNullElse(() -> qSession.getUuid(), "no-session")
+ (StringUtils.hasContent(holder) ? ("-" + holder) : "");
Instant now = Instant.now(); Instant now = Instant.now();
ProcessLock processLock = new ProcessLock() ProcessLock processLock = new ProcessLock()
.withKey(key) .withKey(key)
.withProcessLockTypeId(lockType.getId()) .withProcessLockTypeId(lockType.getId())
.withHolder(holder) .withSessionUUID(ObjectUtils.tryAndRequireNonNullElse(() -> qSession.getUuid(), null))
.withUserId(ObjectUtils.tryAndRequireNonNullElse(() -> qSession.getUser().getIdReference(), null))
.withDetails(details)
.withCheckInTimestamp(now); .withCheckInTimestamp(now);
Integer defaultExpirationSeconds = lockType.getDefaultExpirationSeconds(); Integer defaultExpirationSeconds = lockType.getDefaultExpirationSeconds();
@ -126,7 +123,7 @@ public class ProcessLockUtils
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
Serializable id = existingLockRecord.getValue("id"); Serializable id = existingLockRecord.getValue("id");
LOG.info("Existing lock has expired - deleting it and trying again.", logPair("id", id), LOG.info("Existing lock has expired - deleting it and trying again.", logPair("id", id),
logPair("key", key), logPair("type", typeName), logPair("holder", holder), logPair("expiresAtTimestamp", expiresAtTimestamp)); logPair("key", key), logPair("type", typeName), logPair("details", details), logPair("expiresAtTimestamp", expiresAtTimestamp));
new DeleteAction().execute(new DeleteInput(ProcessLock.TABLE_NAME).withPrimaryKey(id)); new DeleteAction().execute(new DeleteInput(ProcessLock.TABLE_NAME).withPrimaryKey(id));
insertOutputRecord = tryToInsert(processLock); insertOutputRecord = tryToInsert(processLock);
} }
@ -146,12 +143,12 @@ public class ProcessLockUtils
// if at this point, we have errors on the last attempted insert, then give up // // if at this point, we have errors on the last attempted insert, then give up //
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
LOG.info("Errors in process lock record after attempted insert", logPair("errors", insertOutputRecord.getErrors()), LOG.info("Errors in process lock record after attempted insert", logPair("errors", insertOutputRecord.getErrors()),
logPair("key", key), logPair("type", typeName), logPair("holder", holder)); logPair("key", key), logPair("type", typeName), logPair("details", details));
throw (new UnableToObtainProcessLockException("A Process Lock already exists for key [" + key + "] of type [" + typeName + "], " + existingLockDetails)); throw (new UnableToObtainProcessLockException("A Process Lock already exists for key [" + key + "] of type [" + typeName + "], " + existingLockDetails));
} }
LOG.info("Created process lock", logPair("id", processLock.getId()), LOG.info("Created process lock", logPair("id", processLock.getId()),
logPair("key", key), logPair("type", typeName), logPair("holder", holder), logPair("expiresAtTimestamp", processLock.getExpiresAtTimestamp())); logPair("key", key), logPair("type", typeName), logPair("details", details), logPair("expiresAtTimestamp", processLock.getExpiresAtTimestamp()));
return new ProcessLock(insertOutputRecord); return new ProcessLock(insertOutputRecord);
} }

View File

@ -42,6 +42,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
@ -125,7 +126,7 @@ class ProcessLockUtilsTest extends BaseTest
////////////////////// //////////////////////
processLock = ProcessLockUtils.create("1", "typeA", "you"); processLock = ProcessLockUtils.create("1", "typeA", "you");
assertNotNull(processLock.getId()); assertNotNull(processLock.getId());
assertThat(processLock.getHolder()).endsWith("you"); assertEquals("you", processLock.getDetails());
assertThatThrownBy(() -> ProcessLockUtils.create("1", "notAType", "you")) assertThatThrownBy(() -> ProcessLockUtils.create("1", "notAType", "you"))
.isInstanceOf(QException.class) .isInstanceOf(QException.class)
@ -150,7 +151,7 @@ class ProcessLockUtilsTest extends BaseTest
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
processLock = ProcessLockUtils.create("1", "typeB", "you", Duration.of(1, ChronoUnit.SECONDS), Duration.of(3, ChronoUnit.SECONDS)); processLock = ProcessLockUtils.create("1", "typeB", "you", Duration.of(1, ChronoUnit.SECONDS), Duration.of(3, ChronoUnit.SECONDS));
assertNotNull(processLock.getId()); assertNotNull(processLock.getId());
assertThat(processLock.getHolder()).endsWith("you"); assertThat(processLock.getDetails()).endsWith("you");
} }
@ -220,26 +221,46 @@ class ProcessLockUtilsTest extends BaseTest
** **
*******************************************************************************/ *******************************************************************************/
@Test @Test
void testHolders() throws QException void testUserAndSessionNullness() throws QException
{
{ {
QContext.getQSession().setUser(new QUser().withIdReference("me")); QContext.getQSession().setUser(new QUser().withIdReference("me"));
assertThat(ProcessLockUtils.create("1", "typeA", null).getHolder()) ProcessLock processLock = ProcessLockUtils.create("1", "typeA", null);
.isEqualTo("me-" + QContext.getQSession().getUuid()); assertNull(processLock.getDetails());
assertEquals("me", processLock.getUserId());
assertEquals(QContext.getQSession().getUuid(), processLock.getSessionUUID());
}
assertThat(ProcessLockUtils.create("2", "typeA", "foo").getHolder()) {
.isEqualTo("me-" + QContext.getQSession().getUuid() + "-foo"); ProcessLock processLock = ProcessLockUtils.create("2", "typeA", "foo");
assertEquals("foo", processLock.getDetails());
assertEquals("me", processLock.getUserId());
assertEquals(QContext.getQSession().getUuid(), processLock.getSessionUUID());
}
{
QContext.getQSession().setUser(null); QContext.getQSession().setUser(null);
assertThat(ProcessLockUtils.create("3", "typeA", "bar").getHolder()) ProcessLock processLock = ProcessLockUtils.create("3", "typeA", "bar");
.isEqualTo("anonymous-" + QContext.getQSession().getUuid() + "-bar"); assertEquals("bar", processLock.getDetails());
assertNull(processLock.getUserId());
assertEquals(QContext.getQSession().getUuid(), processLock.getSessionUUID());
}
{
QContext.getQSession().setUuid(null); QContext.getQSession().setUuid(null);
assertThat(ProcessLockUtils.create("4", "typeA", "baz").getHolder()) ProcessLock processLock = ProcessLockUtils.create("4", "typeA", "baz");
.isEqualTo("anonymous-no-session-baz"); assertEquals("baz", processLock.getDetails());
assertNull(processLock.getUserId());
assertNull(processLock.getSessionUUID());
}
{
QContext.getQSession().setUuid(null); QContext.getQSession().setUuid(null);
assertThat(ProcessLockUtils.create("5", "typeA", "").getHolder()) ProcessLock processLock = ProcessLockUtils.create("5", "typeA", "");
.isEqualTo("anonymous-no-session"); assertEquals("", processLock.getDetails());
assertNull(processLock.getUserId());
assertNull(processLock.getSessionUUID());
}
} }
} }