Skip to content

Commit c3eeb43

Browse files
authored
docs: Add timeout-inside-lock and resource-properties examples (#1014)
1 parent 8561d98 commit c3eeb43

3 files changed

Lines changed: 188 additions & 0 deletions

File tree

src/doc/examples/readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ If you have a question, please open a [GitHub issue](https://github.com/jenkinsc
99
- [Lock specific stages](lock-specific-stages.md)
1010
- [Locking multiple stages in declarative pipeline](locking-multiple-stages-in-declarative-pipeline.md)
1111
- [Locking a random free resource](locking-random-free-resource.md)
12+
- [Resource properties](resource-properties.md)
1213
- [Scripted vs declarative pipeline](scripted-vs-declarative-pipeline.md)
14+
- [Timeout inside lock](timeout-inside-lock.md)
1315
- [Dynamic resource pool expansion](dynamic-resource-pool-expansion.md)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Resource Properties
2+
3+
Resources can have custom **properties** (name:value pairs) that are exposed
4+
as environment variables when the resource is locked.
5+
6+
## Defining properties
7+
8+
Properties can be added to a resource via:
9+
10+
- **Web UI** — Manage Jenkins → Lockable Resources → edit a resource → add properties
11+
- **JCasC** (Jenkins Configuration as Code):
12+
13+
```yaml
14+
unclassified:
15+
lockableResourcesManager:
16+
resources:
17+
- name: "staging-server"
18+
properties:
19+
- name: "HOST"
20+
value: "192.168.1.10"
21+
- name: "PORT"
22+
value: "8080"
23+
```
24+
25+
## Accessing properties in a pipeline
26+
27+
Properties are exposed as environment variables **only when the `variable`
28+
parameter is specified** in the `lock()` step.
29+
30+
### Naming pattern
31+
32+
| Variable | Value |
33+
|----------|-------|
34+
| `{variable}` | Comma-separated list of all locked resource names |
35+
| `{variable}0` | Name of the first locked resource |
36+
| `{variable}0_{PROPERTY_NAME}` | Value of that resource's property |
37+
| `{variable}1` | Name of the second locked resource (if any) |
38+
| `{variable}1_{PROPERTY_NAME}` | Value of the second resource's property |
39+
40+
### Example: Read properties after locking by name
41+
42+
```groovy
43+
pipeline {
44+
agent any
45+
stages {
46+
stage('Deploy') {
47+
options {
48+
lock(resource: 'staging-server', variable: 'LOCKED')
49+
}
50+
steps {
51+
echo "Resource: ${env.LOCKED0}" // staging-server
52+
echo "Host: ${env.LOCKED0_HOST}" // 192.168.1.10
53+
echo "Port: ${env.LOCKED0_PORT}" // 8080
54+
}
55+
}
56+
}
57+
}
58+
```
59+
60+
### Example: Lock by label and read properties
61+
62+
```groovy
63+
pipeline {
64+
agent any
65+
stages {
66+
stage('Test') {
67+
options {
68+
lock(label: 'gpu', quantity: 1, variable: 'GPU')
69+
}
70+
steps {
71+
echo "Got: ${env.GPU0}"
72+
echo "GPU model: ${env.GPU0_MODEL}"
73+
}
74+
}
75+
}
76+
}
77+
```
78+
79+
## Filtering resources by properties
80+
81+
Use a `resourceMatchScript` to lock only resources whose properties match
82+
specific criteria:
83+
84+
```groovy
85+
lock(extra: [
86+
[$class: 'LockableResourcesStruct',
87+
resourceMatchScript: [
88+
$class: 'SecureGroovyScript',
89+
script: '''
90+
resourceInstance.properties.any {
91+
it.name == "ENV" && it.value == "staging"
92+
}
93+
''',
94+
sandbox: true
95+
],
96+
resourceNumber: '1'
97+
]
98+
]) {
99+
echo "Got a staging resource: ${env.LOCKED_RESOURCE0}"
100+
}
101+
```
102+
103+
## Common pitfalls
104+
105+
1. **Missing `variable` parameter** — without it, no environment variables are
106+
created. This is the most common reason properties appear to be `null`.
107+
2. **Property name is case-sensitive** — if the property is named `host`, the
108+
env var is `LOCKED0_host`, not `LOCKED0_HOST`.
109+
3. **Properties are only available inside the lock block** — they cannot be
110+
accessed after the lock is released.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Timeout Inside Lock
2+
3+
When a pipeline uses both `timeout` and `lock`, the placement of `timeout`
4+
determines whether queue wait time counts against the deadline.
5+
6+
## Problem
7+
8+
If `timeout` wraps the entire pipeline or stage, the clock starts before the
9+
lock is acquired. A job that waits a long time in the queue may time out
10+
before it gets a chance to run:
11+
12+
```groovy
13+
pipeline {
14+
agent any
15+
options {
16+
// Clock starts immediately — includes queue wait time!
17+
timeout(time: 5, unit: 'HOURS')
18+
}
19+
stages {
20+
stage('Deploy') {
21+
steps {
22+
lock('my-resource') {
23+
echo 'Deploying...'
24+
}
25+
}
26+
}
27+
}
28+
}
29+
```
30+
31+
## Solution
32+
33+
Place `timeout` **inside** `lock` so the countdown begins only after the
34+
resource has been acquired:
35+
36+
```groovy
37+
pipeline {
38+
agent any
39+
stages {
40+
stage('Deploy') {
41+
steps {
42+
lock('my-resource') {
43+
timeout(time: 5, unit: 'HOURS') {
44+
echo 'Deploying...'
45+
}
46+
}
47+
}
48+
}
49+
}
50+
}
51+
```
52+
53+
This way a job can wait in the queue as long as necessary without the
54+
timeout expiring prematurely.
55+
56+
## Stage-level variant
57+
58+
The same pattern works with `options` at the stage level:
59+
60+
```groovy
61+
pipeline {
62+
agent any
63+
stages {
64+
stage('Deploy') {
65+
options {
66+
lock('my-resource')
67+
}
68+
steps {
69+
timeout(time: 5, unit: 'HOURS') {
70+
echo 'Deploying...'
71+
}
72+
}
73+
}
74+
}
75+
}
76+
```

0 commit comments

Comments
 (0)