You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2023/06/30 12:10:52 UTC
[brooklyn-server] 02/03: make attributeWhenReady in workflow not timeout/abort on start/stop or abort
This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit b4fd8d634b44981f28d3c323b55acfdf3930478f
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Fri Jun 30 13:08:45 2023 +0100
make attributeWhenReady in workflow not timeout/abort on start/stop or abort
previous impl did it for all templates; now we do it just for workflow templates
---
.../camp/brooklyn/WorkflowExpressionsYamlTest.java | 4 +-
.../core/sensor/DependentConfiguration.java | 18 ++++----
.../workflow/WorkflowExpressionResolution.java | 2 +-
.../brooklyn/util/core/text/TemplateProcessor.java | 48 ++++++++++++++++++----
4 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
index 3036d535b1..0b11eabba1 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java
@@ -226,7 +226,7 @@ public class WorkflowExpressionsYamlTest extends AbstractYamlTest {
}
@Test
- public void testWorkflowExpressionAllowsOnFire() throws Exception {
+ public void testWorkflowTemplateExpressionAllowsOnFire() throws Exception {
Entity entity = createEntity();
WorkflowExecutionContext workflow = invocationWorkflowOnLastEntity(
" - step: transform ${entity.attributeWhenReady.foo} | wait | set foo_in_workflow",
@@ -248,7 +248,7 @@ public class WorkflowExpressionsYamlTest extends AbstractYamlTest {
}
@Test
- public void testDSLExpressionAbortWhenOnFire() throws Exception {
+ public void testBrooklynDslExpressionAbortWhenOnFire() throws Exception {
createEntity();
WorkflowExecutionContext workflow = invocationWorkflowOnLastEntity(
" - step: transform $brooklyn:attributeWhenReady(\"foo\") | wait | set foo_in_workflow",
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
index 351677bcb0..eb4ee249fa 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
@@ -114,14 +114,16 @@ public class DependentConfiguration {
private DependentConfiguration() {}
/**
- * Default readiness is Groovy truth.
- *
+ * Default readiness is Groovy truth, with timeout.
* @see #attributeWhenReady(Entity, AttributeSensor, Predicate)
*/
public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor) {
return attributeWhenReady(source, sensor, JavaGroovyEquivalents.groovyTruthPredicate());
}
+ /**
+ * @see #attributeWhenReadyAllowingOnFire(Entity, AttributeSensor, Predicate)
+ */
public static <T> Task<T> attributeWhenReadyAllowingOnFire(Entity source, AttributeSensor<T> sensor) {
return attributeWhenReadyAllowingOnFire(source, sensor, JavaGroovyEquivalents.groovyTruthPredicate());
}
@@ -136,7 +138,11 @@ public class DependentConfiguration {
}
/** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value;
- * particular useful in Entity configuration where config will block until Tasks have a value
+ * particular useful in Entity configuration where config will block until Tasks have a value.
+ * This task will fail if the entity goes on fire and timeout after 1 minute if starting or stopping,
+ * so is suitable for use in contexts where there is not a straightforward way to bail out in the case of those events
+ * (such as resolving template files as part of an upload).
+ * If this is not desired see {@link #attributeWhenReadyAllowingOnFire(Entity, AttributeSensor, Predicate)}.
*/
public static <T> Task<T> attributeWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) {
Builder<T, T> builder = builder().attributeWhenReady(source, sensor);
@@ -145,11 +151,9 @@ public class DependentConfiguration {
}
- /** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value;
- * particular useful in Entity configuration where config will block until Tasks have a value
- */
+ /** as {@link #attributeWhenReady(Entity, AttributeSensor, Predicate)} but with no timeout and not aborting if the entity goes on fire. */
public static <T> Task<T> attributeWhenReadyAllowingOnFire(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) {
- Builder<T, T> builder = builder().attributeWhenReadyAllowingOnFire(source, sensor).timeoutIfStoppingOrDestroyed(Duration.ONE_MINUTE);
+ Builder<T, T> builder = builder().attributeWhenReadyAllowingOnFire(source, sensor);
if (ready != null) builder.readiness(ready);
return builder.build();
diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
index 76bc842329..14dde15a3a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
+++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java
@@ -604,7 +604,7 @@ public class WorkflowExpressionResolution {
boolean ourWait = interruptSetIfNeededToPreventWaiting();
try {
- result = TemplateProcessor.processTemplateContents("workflow", expression, model, true, false, errorMode);
+ result = TemplateProcessor.processTemplateContentsForWorkflow("workflow", expression, model, true, false, errorMode);
} catch (Exception e) {
Exception e2 = e;
if (wrappingMode.deferAndRetryErroneousExpressions) {
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
index 771fe150fb..ba65c16f7a 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
@@ -41,7 +41,6 @@ import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.effector.EffectorBase;
import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityAsserts;
import org.apache.brooklyn.core.entity.EntityInternal;
import org.apache.brooklyn.core.location.internal.LocationInternal;
import org.apache.brooklyn.core.sensor.DependentConfiguration;
@@ -87,6 +86,7 @@ public class TemplateProcessor {
static ThreadLocalStack<Map<TemplateModel,Object>> TEMPLATE_MODEL_UNWRAP_CACHE = new ThreadLocalStack<>(true);
static ThreadLocalStack<String> TEMPLATE_FILE_WANTING_LEGACY_SYNTAX = new ThreadLocalStack<>(true);
+ static ThreadLocalStack<Boolean> IS_FOR_WORKFLOW = new ThreadLocalStack<>(true);
public interface UnwrappableTemplateModel {
Maybe<Object> unwrap();
@@ -600,16 +600,19 @@ public class TemplateProcessor {
return Maybe.of(entity);
}
- enum SensorResolutionMode { SENSOR_DEFINITION, ATTRIBUTE_VALUE, ATTRIBUTE_WHEN_READY }
+ enum SensorResolutionMode { SENSOR_DEFINITION,
+ ATTRIBUTE_VALUE,
+ ATTRIBUTE_WHEN_READY_FOR_TEMPLATES,
+ ATTRIBUTE_WHEN_READY_FOR_WORKFLOW }
protected EntityAttributeTemplateModel(EntityInternal entity, SensorResolutionMode mode) {
this.entity = entity;
if (TEMPLATE_FILE_WANTING_LEGACY_SYNTAX.peek().isPresentAndNonNull()) {
// in templates, we have only ever supported attribute when ready. preserve that for now, but warn of deprecation.
- if (mode != SensorResolutionMode.ATTRIBUTE_WHEN_READY) {
+ if (mode != SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES) {
log.warn("Using deprecated legacy attributeWhenReady behaviour of ${entity.attribute...} or ${entity.sensor...}. Template should be updated to use ${entity.attributeWhenReady...} if that is required: "
+ TEMPLATE_FILE_WANTING_LEGACY_SYNTAX.peek());
- mode = SensorResolutionMode.ATTRIBUTE_WHEN_READY;
+ mode = SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES;
}
}
this.mode = mode;
@@ -625,9 +628,12 @@ public class TemplateProcessor {
Object result;
try {
result =
- mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY ?
- ((EntityInternal)entity).getExecutionContext().get( DependentConfiguration.attributeWhenReadyAllowingOnFire(entity,
+ mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES ?
+ ((EntityInternal)entity).getExecutionContext().get( DependentConfiguration.attributeWhenReady(entity,
Sensors.builder(Object.class, key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build()))
+ : mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_WORKFLOW ?
+ ((EntityInternal)entity).getExecutionContext().get( DependentConfiguration.attributeWhenReadyAllowingOnFire(entity,
+ Sensors.builder(Object.class, key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build()))
: mode == SensorResolutionMode.ATTRIBUTE_VALUE ?
entity.sensors().get( Sensors.newSensor(Object.class, key) )
: mode == SensorResolutionMode.SENSOR_DEFINITION ?
@@ -679,8 +685,9 @@ public class TemplateProcessor {
protected final EntityDriver driver;
protected final ManagementContext mgmt;
protected final DotSplittingTemplateModel extraSubstitutionsModel;
+ protected boolean isForWorkflow = false;
- // TODO the extra substitutions here (and in LocationAndMapTemplateModel) could be replaced with
+ // note: the extra substitutions here (and in LocationAndMapTemplateModel) could be replaced with
// FirstAvailableTemplateModel(entityModel, mapHashModel)
protected EntityAndMapTemplateModel(ManagementContext mgmt, EntityInternal entity, EntityDriver driver) {
@@ -690,6 +697,11 @@ public class TemplateProcessor {
extraSubstitutionsModel = new DotSplittingTemplateModel(null);
}
+ public EntityAndMapTemplateModel setIsForWorkflow(boolean isForWorkflow) {
+ this.isForWorkflow = isForWorkflow;
+ return this;
+ }
+
@Override
public Maybe<Object> unwrap() {
return Maybe.ofDisallowingNull(entity!=null ? entity : mgmt!=null ? mgmt : extraSubstitutionsModel.unwrap().orNull());
@@ -700,7 +712,15 @@ public class TemplateProcessor {
}
public static TemplateHashModel forEntity(Entity entity, Map<String,? extends Object> extraSubstitutions) {
- return new FirstAvailableTemplateModel(new EntityAndMapTemplateModel(null, (EntityInternal) entity, null), wrappedBeanToHashOrNull(entity), dotOrNull(extraSubstitutions));
+ EntityAndMapTemplateModel entityModel = new EntityAndMapTemplateModel(null, (EntityInternal) entity, null);
+ if (Boolean.TRUE.equals(IS_FOR_WORKFLOW.peek().orNull())) entityModel.setIsForWorkflow(true);
+ return new FirstAvailableTemplateModel(entityModel, wrappedBeanToHashOrNull(entity), dotOrNull(extraSubstitutions));
+ }
+
+ public static TemplateHashModel forEntityPossiblyInWorkflow(Entity entity, Map<String,? extends Object> extraSubstitutions, boolean isInWorkflow) {
+ return new FirstAvailableTemplateModel(
+ new EntityAndMapTemplateModel(null, (EntityInternal) entity, null).setIsForWorkflow(isInWorkflow),
+ wrappedBeanToHashOrNull(entity), dotOrNull(extraSubstitutions));
}
public static TemplateHashModel forManagementContext(ManagementContext mgmt, Map<String,? extends Object> extraSubstitutions) {
@@ -765,7 +785,8 @@ public class TemplateProcessor {
return wrapAsTemplateModel( entity instanceof Group ? ((Group)entity).getMembers() : MutableList.of() );
if ("sensor".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_VALUE);
if ("attribute".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_VALUE);
- if ("attributeWhenReady".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_WHEN_READY);
+ if ("attributeWhenReady".equals(key)) return new EntityAttributeTemplateModel(entity,
+ isForWorkflow ? EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_WORKFLOW : EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES);
// new option
if ("sensor_definition".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.SENSOR_DEFINITION);
if ("effector".equals(key)) return wrapAsTemplateModel(Maps.transformValues(entity.getMutableEntityType().getEffectors(), EffectorBase::of));
@@ -983,6 +1004,15 @@ public class TemplateProcessor {
}
}
+ public static Object processTemplateContentsForWorkflow(String context, String templateContents, final TemplateHashModel substitutions, boolean allowSingleVariableObject, boolean logErrors, InterpolationErrorMode errorMode) {
+ try {
+ IS_FOR_WORKFLOW.push(true);
+ return processTemplateContents(context, templateContents, substitutions, allowSingleVariableObject, logErrors, errorMode);
+ } finally {
+ IS_FOR_WORKFLOW.pop();
+ }
+ }
+
public enum InterpolationErrorMode {
FAIL,
BLANK,