Skip to content

Commit

Permalink
Lockable priority strategy (#632)
Browse files Browse the repository at this point in the history
  • Loading branch information
mPokornyETM authored Mar 19, 2024
1 parent b05f8a4 commit 28be4cc
Show file tree
Hide file tree
Showing 29 changed files with 942 additions and 207 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,41 @@ lock(resource: 'staging-server', inversePrecedence: true) {
}
```

> It is not allowed to mixed **inversePrecedence** and **priority**.
start time | job | resource | inversePrecedence
------ |--- |--- |---
00:01 | j1 | resource1 | false
00:02 | j2 | resource1 | false
00:03 | j3 | resource1 | true
00:04 | j4 | resource1 | false
00:05 | j5 | resource1 | true
00:06 | j6 | resource1 | false

Resulting lock order: j1 -> j5 -> j3 -> j2 -> j4 -> j6

#### lock (queue) priority

```groovy
lock(resource: 'staging-server', priority: 10) {
node {
servers.deploy 'staging'
}
input message: "Does ${jettyUrl}staging/ look good?"
}
```

start time | job | resource | priority
------ |--- |--- |---
00:01 | j1 | resource1 | 0
00:02 | j2 | resource1 | <default == 0>
00:03 | j3 | resource1 | -1
00:04 | j4 | resource1 | 10
00:05 | j5 | resource1 | -2
00:06 | j6 | resource1 | 100

Resulting lock order: j1 -> j6 -> j4 -> j2 -> j3 -> j5

#### Resolve a variable configured with the resource name and properties

```groovy
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

<properties>
<changelist>999999-SNAPSHOT</changelist>
<jenkins.version>2.387.3</jenkins.version>
<jenkins.version>2.440.1</jenkins.version>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<spotbugs.effort>Max</spotbugs.effort>
<spotbugs.threshold>Low</spotbugs.threshold>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public static void compatibilityMigration() {
queuedContext,
Collections.singletonList(resourceHolder),
resource.getName(),
null);
null,
false,
0);
}
queuedContexts.clear();
}
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/org/jenkins/plugins/lockableresources/LockStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public class LockStep extends Step implements Serializable {
@SuppressFBWarnings(value = "PA_PUBLIC_PRIMITIVE_ATTRIBUTE", justification = "Preserve API compatibility.")
public List<LockStepResource> extra = null;

@SuppressFBWarnings(value = "PA_PUBLIC_PRIMITIVE_ATTRIBUTE", justification = "Preserve API compatibility.")
public int priority = 0;

// it should be LockStep() - without params. But keeping this for backward compatibility
// so `lock('resource1')` still works and `lock(label: 'label1', quantity: 3)` works too (resource
// is not required)
Expand Down Expand Up @@ -105,6 +108,11 @@ public void setQuantity(int quantity) {
this.quantity = quantity;
}

@DataBoundSetter
public void setPriority(int priority) {
this.priority = priority;
}

@DataBoundSetter
public void setExtra(@CheckForNull List<LockStepResource> extra) {
this.extra = extra;
Expand Down Expand Up @@ -184,7 +192,11 @@ public String toString() {
.map(res -> "{" + res.toString() + "}")
.collect(Collectors.joining(","));
} else if (resource != null || label != null) {
return LockStepResource.toString(resource, label, quantity);
String ret = LockStepResource.toString(resource, label, quantity);
if (this.priority != 0) {
ret += ", Priority: " + this.priority;
}
return ret;
} else {
return "nothing";
}
Expand All @@ -193,7 +205,7 @@ public String toString() {
// -------------------------------------------------------------------------
/** Label and resource are mutual exclusive. */
public void validate() {
LockStepResource.validate(resource, label, resourceSelectStrategy, extra);
LockStepResource.validate(resource, label, resourceSelectStrategy, extra, priority, inversePrecedence);
}

// -------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public boolean start() throws Exception {
resourceNames.put(resource.getName(), resource.getProperties());
}
}
LockStepExecution.proceed(resourceNames, getContext(), step.toString(), step.variable, step.inversePrecedence);
LockStepExecution.proceed(resourceNames, getContext(), step.toString(), step.variable);

return false;
}
Expand All @@ -120,7 +120,13 @@ private void onLockFailed(PrintStream logger, List<LockableResourcesStruct> reso
LockableResourcesManager.printLogs(
"[" + step + "] is not free, waiting for execution ...", Level.FINE, LOGGER, logger);
LockableResourcesManager lrm = LockableResourcesManager.get();
lrm.queueContext(getContext(), resourceHolderList, step.toString(), step.variable);
lrm.queueContext(
getContext(),
resourceHolderList,
step.toString(),
step.variable,
step.inversePrecedence,
step.priority);
}
}

Expand All @@ -144,8 +150,7 @@ public static void proceed(
final LinkedHashMap<String, List<LockableResourceProperty>> lockedResources,
StepContext context,
String resourceDescription,
final String variable,
boolean inversePrecedence) {
final String variable) {
Run<?, ?> build;
FlowNode node = null;
PrintStream logger = null;
Expand All @@ -165,8 +170,7 @@ public static void proceed(
LockedResourcesBuildAction.updateAction(build, new ArrayList<>(lockedResources.keySet()));
PauseAction.endCurrentPause(node);
BodyInvoker bodyInvoker = context.newBodyInvoker()
.withCallback(new Callback(
new ArrayList<>(lockedResources.keySet()), resourceDescription, inversePrecedence));
.withCallback(new Callback(new ArrayList<>(lockedResources.keySet()), resourceDescription));
if (variable != null && !variable.isEmpty()) {
// set the variable for the duration of the block
bodyInvoker.withContext(
Expand Down Expand Up @@ -210,18 +214,15 @@ private static final class Callback extends BodyExecutionCallback.TailCall {
private static final long serialVersionUID = -2024890670461847666L;
private final List<String> resourceNames;
private final String resourceDescription;
private final boolean inversePrecedence;

Callback(List<String> resourceNames, String resourceDescription, boolean inversePrecedence) {
Callback(List<String> resourceNames, String resourceDescription) {
this.resourceNames = resourceNames;
this.resourceDescription = resourceDescription;
this.inversePrecedence = inversePrecedence;
}

@Override
protected void finished(StepContext context) throws Exception {
LockableResourcesManager.get()
.unlockNames(this.resourceNames, context.get(Run.class), this.inversePrecedence);
LockableResourcesManager.get().unlockNames(this.resourceNames, context.get(Run.class));
LockableResourcesManager.printLogs(
"Lock released on resource [" + resourceDescription + "]",
Level.FINE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,27 @@ public static String toString(String resource, String label, int quantity) {
}
// make sure there is an actual resource specified
if (resource != null) {
return resource;
return "Resource: " + resource;
}
return "[no resource/label specified - probably a bug]";
}

// -------------------------------------------------------------------------
/** Label and resource are mutual exclusive. */
public void validate() {
validate(resource, label, null, false);
validate(resource, label, null, false, 0, false);
}

// -------------------------------------------------------------------------
/** Validate input parameters*/
public static void validate(
String resource, String label, String resourceSelectStrategy, List<LockStepResource> extra) {
validate(resource, label, resourceSelectStrategy, extra != null);
String resource,
String label,
String resourceSelectStrategy,
List<LockStepResource> extra,
int priority,
boolean inversePrecedence) {
validate(resource, label, resourceSelectStrategy, extra != null, priority, inversePrecedence);
if (extra != null) {
for (LockStepResource e : extra) {
e.validate();
Expand All @@ -103,10 +108,21 @@ public static void validate(
* Label and resource are mutual exclusive. The label, if provided, must be configured (at least
* one resource must have this label).
*/
public static void validate(String resource, String label, String resourceSelectStrategy, boolean hasExtra) {
public static void validate(
String resource,
String label,
String resourceSelectStrategy,
boolean hasExtra,
int priority,
boolean inversePrecedence) {
if (!hasExtra && label == null && resource == null) {
throw new IllegalArgumentException(Messages.error_labelOrNameMustBeSpecified());
}

if (priority != 0 && inversePrecedence) {
throw new IllegalArgumentException(Messages.error_inversePrecedenceAndPriorityAreSet());
}

if (label != null && !label.isEmpty() && resource != null && !resource.isEmpty()) {
throw new IllegalArgumentException(Messages.error_labelAndNameSpecified());
}
Expand Down
Loading

0 comments on commit 28be4cc

Please sign in to comment.