From fa80d7a916df38f355cc442d44253f8705e6b1b6 Mon Sep 17 00:00:00 2001 From: Deepak Dixit Date: Wed, 6 May 2026 12:57:37 +0530 Subject: [PATCH 1/2] Enhance service semaphore to support parameter-based locking (OFBIZ-13395) - Added semaphore-parameter-name attribute to service definitions - Extended ServiceSemaphore to include parameterValue - Updated locking logic to use (serviceName, parameterValue) scope - Modified dispatcher to pass parameter values from service requests - Allows concurrent execution of the same service for different parameter values - Enables finer-grained concurrency control compared to service-level locking --- applications/datamodel/DATAMODEL_CHANGES.adoc | 1 + framework/service/dtd/services.xsd | 1 + framework/service/entitydef/entitymodel.xml | 2 ++ .../apache/ofbiz/service/ModelService.java | 20 +++++++++++++++++++ .../ofbiz/service/ModelServiceReader.java | 5 +++++ .../ofbiz/service/ServiceDispatcher.java | 9 ++++++++- .../service/semaphore/ServiceSemaphore.java | 10 ++++++---- 7 files changed, 43 insertions(+), 5 deletions(-) diff --git a/applications/datamodel/DATAMODEL_CHANGES.adoc b/applications/datamodel/DATAMODEL_CHANGES.adoc index b087bd6efcd..d337d5f740a 100644 --- a/applications/datamodel/DATAMODEL_CHANGES.adoc +++ b/applications/datamodel/DATAMODEL_CHANGES.adoc @@ -419,6 +419,7 @@ No changes |SalaryStep |lastModifiedByUserLogin |Added |No |NA |SalesOpportunity |nextStepDate |Added |No |NA |ServiceSemaphore |lockedByInstanceId |Added |No |NA +|ServiceSemaphore |parameterValue |Added |Yes |NA |ShoppingListItem |modifiedPrice |Added |No |NA |SkillType |parentTypeId |Added |No |NA |SkillType |hasTable |Added |No |NA diff --git a/framework/service/dtd/services.xsd b/framework/service/dtd/services.xsd index e7e90b40493..87d601821a1 100644 --- a/framework/service/dtd/services.xsd +++ b/framework/service/dtd/services.xsd @@ -131,6 +131,7 @@ under the License. + diff --git a/framework/service/entitydef/entitymodel.xml b/framework/service/entitydef/entitymodel.xml index 83ffa19436a..f1768260f45 100644 --- a/framework/service/entitydef/entitymodel.xml +++ b/framework/service/entitydef/entitymodel.xml @@ -212,10 +212,12 @@ under the License. + + diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java index 46ca08d8314..72df2f0b392 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java @@ -185,6 +185,9 @@ public class ModelService extends AbstractMap implements Seriali /** Semaphore sleep time (in milliseconds) */ private int semaphoreSleep; + /** Semaphore parameter name */ + private String semaphoreParameterName; + /** Require a new transaction for this service */ private boolean hideResultInLog; @@ -398,6 +401,14 @@ public void setSemaphoreSleep(int semaphoreSleep) { this.semaphoreSleep = semaphoreSleep; } + /** + * Sets semaphore parameter name. + * @param semaphoreParameterName the semaphore sleep + */ + public void setSemaphoreParameterName(String semaphoreParameterName) { + this.semaphoreParameterName = semaphoreParameterName; + } + /** * Sets hide result in log. * @param hideResultInLog the hide result in log @@ -574,6 +585,14 @@ public int getSemaphoreSleep() { return semaphoreSleep; } + /** + * Gets semaphore parameter name. + * @return the semaphore parameter name + */ + public String getSemaphoreParameterName() { + return semaphoreParameterName; + } + /** * Gets impl services. * @return the impl services @@ -791,6 +810,7 @@ public ModelService(ModelService model) { this.debug = model.debug; this.semaphoreWait = model.semaphoreWait; this.semaphoreSleep = model.semaphoreSleep; + this.semaphoreParameterName = model.semaphoreParameterName; this.contextInfo = model.contextInfo; this.definitionLocation = model.definitionLocation; this.description = model.description; diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java index 72252a82430..badfd02f97e 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java @@ -214,6 +214,11 @@ private ModelService createModelService(Element serviceElement, String resourceL } service.setSemaphoreSleep(semaphoreSleep); + String semaphoreParamName = UtilXml.checkEmpty(serviceElement.getAttribute("semaphore-parameter-name")); + if (UtilValidate.isNotEmpty(semaphoreParamName)) { + service.setSemaphoreParameterName(semaphoreParamName); + } + // set the max retry field String maxRetryStr = UtilXml.checkEmpty(serviceElement.getAttribute("max-retry")); int maxRetry = 0; diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java b/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java index bde06cc15b1..0b2116f2c26 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java @@ -284,9 +284,16 @@ public Map runSync(String localName, ModelService modelService, boolean isError = false; boolean beganTrans = false; try { + String semaphoreParamValue = "_NA_"; + String semaphoreParamName = modelService.getSemaphoreParameterName(); + if (UtilValidate.isNotEmpty(semaphoreParamName)) { + Object paramObj = params.get(semaphoreParamName); + semaphoreParamValue = (paramObj != null) ? paramObj.toString() : "_NULL_"; + } + // check for semaphore and acquire a lock if ("wait".equals(modelService.getSemaphore()) || "fail".equals(modelService.getSemaphore())) { - lock = new ServiceSemaphore(delegator, modelService); + lock = new ServiceSemaphore(delegator, modelService, semaphoreParamValue); lock.acquire(); } diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java b/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java index a3a5bb4a284..47d731a4bd3 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java @@ -50,17 +50,19 @@ public final class ServiceSemaphore { private Delegator delegator; private GenericValue lock; private ModelService model; + private String parameterValue; private int wait = 0; private int mode; private Timestamp lockTime = null; - public ServiceSemaphore(Delegator delegator, ModelService model) { + public ServiceSemaphore(Delegator delegator, ModelService model, String parameterValue) { this.delegator = delegator; this.mode = "wait".equals(model.getSemaphore()) ? SEMAPHORE_MODE_WAIT : ("fail".equals(model.getSemaphore()) ? SEMAPHORE_MODE_FAIL : SEMAPHORE_MODE_NONE); this.model = model; this.lock = null; + this.parameterValue = parameterValue; } /** @@ -147,8 +149,8 @@ private boolean checkLockNeedToWait() throws SemaphoreFailException { try { if (EntityQuery.use(delegator).from("ServiceSemaphore") - .where("serviceName", model.getName()).queryCount() == 0) { - semaphore = delegator.makeValue("ServiceSemaphore", "serviceName", model.getName(), + .where("serviceName", model.getName(), "parameterValue", parameterValue).queryCount() == 0) { + semaphore = delegator.makeValue("ServiceSemaphore", "serviceName", model.getName(), "parameterValue", parameterValue, "lockedByInstanceId", JobManager.INSTANCE_ID, "lockThread", threadName, "lockTime", lockTime); // use the special method below so we can reuse the unique tx functions @@ -196,7 +198,7 @@ private synchronized boolean dbWrite(GenericValue value, boolean delete) { } else { // Last check before inserting data in this transaction to avoid error log isError = EntityQuery.use(delegator).from("ServiceSemaphore") - .where("serviceName", model.getName()).queryCount() != 0; + .where("serviceName", model.getName(), "parameterValue", parameterValue).queryCount() != 0; if (!isError) { lock = value.create(); } From ecc9f31fd2e9b40290a646b66f1a2fcb7b4d5c82 Mon Sep 17 00:00:00 2001 From: Deepak Dixit Date: Mon, 13 Jul 2026 13:41:03 +0530 Subject: [PATCH 2/2] Improved: Rework parameter-based service semaphore locking per review feedback (OFBIZ-13395) - Replaced the service-level semaphore-parameter-name attribute with an include-in-lock attribute on the service attribute element, so the lock definition always references real service parameters and several parameters can be combined in the lock - include-in-lock is only allowed on IN or INOUT attributes; invalid usage is reported at service definition load time - include-in-lock can also be set through the override element, useful for attributes defined via auto-attributes or inherited from an interface service; the mode check is then applied when the override is merged in ModelService.interfaceUpdate - Reverted the ServiceSemaphore entity change: instead of adding a parameterValue primary key field, the values of the flagged attributes are hashed (truncated SHA-256) and appended to the service name, keeping the existing single-field primary key - Behavior is unchanged for services without flagged attributes: the lock name remains the plain service name --- applications/datamodel/DATAMODEL_CHANGES.adoc | 1 - framework/service/dtd/services.xsd | 22 +++++++- framework/service/entitydef/entitymodel.xml | 2 - .../org/apache/ofbiz/service/ModelParam.java | 19 +++++++ .../apache/ofbiz/service/ModelService.java | 28 +++------- .../ofbiz/service/ModelServiceReader.java | 24 ++++++-- .../ofbiz/service/ServiceDispatcher.java | 9 +-- .../service/semaphore/ServiceSemaphore.java | 55 ++++++++++++++++--- 8 files changed, 115 insertions(+), 45 deletions(-) diff --git a/applications/datamodel/DATAMODEL_CHANGES.adoc b/applications/datamodel/DATAMODEL_CHANGES.adoc index f358291f8ea..024a6486db5 100644 --- a/applications/datamodel/DATAMODEL_CHANGES.adoc +++ b/applications/datamodel/DATAMODEL_CHANGES.adoc @@ -419,7 +419,6 @@ No changes |SalaryStep |lastModifiedByUserLogin |Added |No |NA |SalesOpportunity |nextStepDate |Added |No |NA |ServiceSemaphore |lockedByInstanceId |Added |No |NA -|ServiceSemaphore |parameterValue |Added |Yes |NA |ShoppingListItem |modifiedPrice |Added |No |NA |SkillType |parentTypeId |Added |No |NA |SkillType |hasTable |Added |No |NA diff --git a/framework/service/dtd/services.xsd b/framework/service/dtd/services.xsd index b9fa09f0204..7d9ce2b986e 100644 --- a/framework/service/dtd/services.xsd +++ b/framework/service/dtd/services.xsd @@ -117,7 +117,6 @@ under the License. - @@ -356,6 +355,19 @@ under the License. + + + + Only relevant when the service defines a semaphore (wait or fail). + If set to true the value of this attribute is included in the semaphore lock key: + the values of all attributes flagged with include-in-lock are hashed and the hash is + appended to the service name used to acquire the lock, so calls with different values + can run concurrently while calls with the same values are still serialized. + Can only be used on IN or INOUT attributes, ignored otherwise. + An optional attribute can be flagged too, its value is then included as null when not passed. + + + The value specified will be used for the attribute if no value is passed in. @@ -437,6 +449,14 @@ under the License. + + + + See the documentation on the include-in-lock attribute of the "attribute" element. + Useful to flag an attribute defined through auto-attributes. + + + diff --git a/framework/service/entitydef/entitymodel.xml b/framework/service/entitydef/entitymodel.xml index 4d4ad120874..0eef0e29113 100644 --- a/framework/service/entitydef/entitymodel.xml +++ b/framework/service/entitydef/entitymodel.xml @@ -222,12 +222,10 @@ under the License. - - diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java index 28dc20e06a9..5b4f5ea6b2b 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java @@ -95,6 +95,8 @@ public class ModelParam implements Serializable { /** Is this Parameter set internally? */ private boolean internal = false; + /** Is this Parameter value included in the service semaphore lock key? */ + private boolean includeInLock = false; /** Children attributes*/ private ArrayList children = null; @@ -122,6 +124,7 @@ public ModelParam(ModelParam param) { this.overrideFormDisplay = param.overrideFormDisplay; this.allowHtml = param.allowHtml; this.internal = param.internal; + this.includeInLock = param.includeInLock; } /** @@ -484,6 +487,22 @@ public boolean isOptional() { return this.optional; } + /** + * Is include in lock boolean. + * @return the boolean + */ + public boolean isIncludeInLock() { + return this.includeInLock; + } + + /** + * Sets include in lock. + * @param includeInLock the include in lock + */ + public void setIncludeInLock(boolean includeInLock) { + this.includeInLock = includeInLock; + } + /** * Gets default value. * @return the default value diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java index 1bbfa395000..40b0677b99a 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java @@ -182,9 +182,6 @@ public class ModelService extends AbstractMap implements Seriali /** Semaphore sleep time (in milliseconds) */ private int semaphoreSleep; - /** Semaphore parameter name */ - private String semaphoreParameterName; - /** Require a new transaction for this service */ private boolean hideResultInLog; @@ -390,14 +387,6 @@ public void setSemaphoreSleep(int semaphoreSleep) { this.semaphoreSleep = semaphoreSleep; } - /** - * Sets semaphore parameter name. - * @param semaphoreParameterName the semaphore sleep - */ - public void setSemaphoreParameterName(String semaphoreParameterName) { - this.semaphoreParameterName = semaphoreParameterName; - } - /** * Sets hide result in log. * @param hideResultInLog the hide result in log @@ -566,14 +555,6 @@ public int getSemaphoreSleep() { return semaphoreSleep; } - /** - * Gets semaphore parameter name. - * @return the semaphore parameter name - */ - public String getSemaphoreParameterName() { - return semaphoreParameterName; - } - /** * Gets impl services. * @return the impl services @@ -791,7 +772,6 @@ public ModelService(ModelService model) { this.debug = model.debug; this.semaphoreWait = model.semaphoreWait; this.semaphoreSleep = model.semaphoreSleep; - this.semaphoreParameterName = model.semaphoreParameterName; this.contextInfo = model.contextInfo; this.definitionLocation = model.definitionLocation; this.description = model.description; @@ -1932,6 +1912,14 @@ public synchronized void interfaceUpdate(DispatchContext dctx) throws GenericSer if (overrideParam.isOverrideOptional()) { existingParam.setOptional(overrideParam.isOptional()); } + if (overrideParam.isIncludeInLock()) { + if (!existingParam.isIn()) { + Debug.logError("Attribute [" + overrideParam.getName() + "] of service [" + this.name + + "] cannot be included in the semaphore lock key: only IN or INOUT attributes are allowed", MODULE); + } else { + existingParam.setIncludeInLock(true); + } + } if (UtilValidate.isNotEmpty(overrideParam.getAllowHtml())) { existingParam.setAllowHtml(overrideParam.getAllowHtml()); } diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java index c79b4cbb895..02b8af753c2 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java @@ -213,11 +213,6 @@ private ModelService createModelService(Element serviceElement, String resourceL } service.setSemaphoreSleep(semaphoreSleep); - String semaphoreParamName = UtilXml.checkEmpty(serviceElement.getAttribute("semaphore-parameter-name")); - if (UtilValidate.isNotEmpty(semaphoreParamName)) { - service.setSemaphoreParameterName(semaphoreParamName); - } - // set the max retry field String maxRetryStr = UtilXml.checkEmpty(serviceElement.getAttribute("max-retry")); int maxRetry = 0; @@ -534,6 +529,16 @@ private static ModelParam createAttrDef(Element attribute, ModelParam parentPara param.setDefaultValue(defValue.intern()); } + // flag the attribute to include its value in the service semaphore lock key + if ("true".equalsIgnoreCase(attribute.getAttribute("include-in-lock"))) { + if (!param.isIn()) { + Debug.logError("Attribute [" + param.getName() + "] of service [" + service.getName() + + "] cannot be included in the semaphore lock key: only IN or INOUT attributes are allowed", MODULE); + } else { + param.setIncludeInLock(true); + } + } + // set the entity name to the default if not specified if (param.getEntityName().length() == 0) { param.setEntityName(service.getDefaultEntityName()); @@ -600,6 +605,15 @@ private static void createOverrideDefs(Element baseElement, ModelService service param.setAllowHtml(UtilXml.checkEmpty(overrideElement.getAttribute("allow-html")).intern()); } + if ("true".equalsIgnoreCase(overrideElement.getAttribute("include-in-lock"))) { + if (!param.isIn()) { + Debug.logError("Attribute [" + param.getName() + "] of service [" + service.getName() + + "] cannot be included in the semaphore lock key: only IN or INOUT attributes are allowed", MODULE); + } else { + param.setIncludeInLock(true); + } + } + // default value String defValue = overrideElement.getAttribute("default-value"); if (UtilValidate.isNotEmpty(defValue)) { diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java b/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java index 9028635d9c6..b2cd77f6438 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java @@ -288,16 +288,9 @@ public Map runSync(String localName, ModelService modelService, boolean isError = false; boolean beganTrans = false; try { - String semaphoreParamValue = "_NA_"; - String semaphoreParamName = modelService.getSemaphoreParameterName(); - if (UtilValidate.isNotEmpty(semaphoreParamName)) { - Object paramObj = params.get(semaphoreParamName); - semaphoreParamValue = (paramObj != null) ? paramObj.toString() : "_NULL_"; - } - // check for semaphore and acquire a lock if ("wait".equals(modelService.getSemaphore()) || "fail".equals(modelService.getSemaphore())) { - lock = new ServiceSemaphore(delegator, modelService, semaphoreParamValue); + lock = new ServiceSemaphore(delegator, modelService, params); lock.acquire(); } diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java b/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java index 47d731a4bd3..d9e5bdf1c3a 100644 --- a/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java +++ b/framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java @@ -18,11 +18,18 @@ *******************************************************************************/ package org.apache.ofbiz.service.semaphore; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.sql.Timestamp; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javax.transaction.Transaction; import org.apache.ofbiz.base.util.Debug; +import org.apache.ofbiz.base.util.StringUtil; import org.apache.ofbiz.base.util.UtilDateTime; import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericEntityException; @@ -30,6 +37,7 @@ import org.apache.ofbiz.entity.transaction.GenericTransactionException; import org.apache.ofbiz.entity.transaction.TransactionUtil; import org.apache.ofbiz.entity.util.EntityQuery; +import org.apache.ofbiz.service.ModelParam; import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.service.job.JobManager; @@ -50,19 +58,50 @@ public final class ServiceSemaphore { private Delegator delegator; private GenericValue lock; private ModelService model; - private String parameterValue; + private String lockName; private int wait = 0; private int mode; private Timestamp lockTime = null; - public ServiceSemaphore(Delegator delegator, ModelService model, String parameterValue) { + public ServiceSemaphore(Delegator delegator, ModelService model, Map context) { this.delegator = delegator; this.mode = "wait".equals(model.getSemaphore()) ? SEMAPHORE_MODE_WAIT : ("fail".equals(model.getSemaphore()) ? SEMAPHORE_MODE_FAIL : SEMAPHORE_MODE_NONE); this.model = model; this.lock = null; - this.parameterValue = parameterValue; + this.lockName = makeLockName(model, context); + } + + /** + * Build the semaphore lock name for a service call. When some service attributes are flagged + * with include-in-lock="true", their values are hashed and the hash is appended to the service + * name so that the lock scope is the combination of the service and those attribute values, + * while the ServiceSemaphore entity keeps its single field primary key. + * @param model the service model + * @param context the service call context + * @return the lock name stored in the ServiceSemaphore serviceName field + */ + private static String makeLockName(ModelService model, Map context) { + List lockParams = model.getInModelParamList().stream() + .filter(ModelParam::isIncludeInLock) + .collect(Collectors.toList()); + if (lockParams.isEmpty()) { + return model.getName(); + } + StringBuilder lockKey = new StringBuilder(); + for (ModelParam lockParam : lockParams) { + Object value = context != null ? context.get(lockParam.getName()) : null; + lockKey.append(lockParam.getName()).append('=').append(value).append(';'); + } + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + String hash = StringUtil.toHexString(digest.digest(lockKey.toString().getBytes(StandardCharsets.UTF_8))); + // the hash is truncated so the lock name fits in the 100 character serviceName field + return model.getName() + "#" + hash.substring(0, 32); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("SHA-256 message digest not available", e); + } } /** @@ -103,7 +142,7 @@ public synchronized boolean release() { private void waitOrFail() throws SemaphoreWaitException, SemaphoreFailException { if (SEMAPHORE_MODE_FAIL == mode) { // fail - throw new SemaphoreFailException("Service [" + model.getName() + "] is locked"); + throw new SemaphoreFailException("Service [" + lockName + "] is locked"); } else if (SEMAPHORE_MODE_WAIT == mode) { // get the wait and sleep values long maxWaitCount = ((model.getSemaphoreWait() * 1000) / model.getSemaphoreSleep()); @@ -126,7 +165,7 @@ private void waitOrFail() throws SemaphoreWaitException, SemaphoreFailException } if (timedOut) { double waitTimeSec = ((System.currentTimeMillis() - lockTime.getTime()) / 1000.0); - String errMsg = "Service [" + model.getName() + "] with wait semaphore exceeded wait timeout, waited [" + String errMsg = "Service [" + lockName + "] with wait semaphore exceeded wait timeout, waited [" + waitTimeSec + "], wait started at " + lockTime; throw new SemaphoreWaitException(errMsg); } @@ -149,8 +188,8 @@ private boolean checkLockNeedToWait() throws SemaphoreFailException { try { if (EntityQuery.use(delegator).from("ServiceSemaphore") - .where("serviceName", model.getName(), "parameterValue", parameterValue).queryCount() == 0) { - semaphore = delegator.makeValue("ServiceSemaphore", "serviceName", model.getName(), "parameterValue", parameterValue, + .where("serviceName", lockName).queryCount() == 0) { + semaphore = delegator.makeValue("ServiceSemaphore", "serviceName", lockName, "lockedByInstanceId", JobManager.INSTANCE_ID, "lockThread", threadName, "lockTime", lockTime); // use the special method below so we can reuse the unique tx functions @@ -198,7 +237,7 @@ private synchronized boolean dbWrite(GenericValue value, boolean delete) { } else { // Last check before inserting data in this transaction to avoid error log isError = EntityQuery.use(delegator).from("ServiceSemaphore") - .where("serviceName", model.getName(), "parameterValue", parameterValue).queryCount() != 0; + .where("serviceName", lockName).queryCount() != 0; if (!isError) { lock = value.create(); }