Skip to content

Commit 3c3e9f5

Browse files
tcuttschristopher-hakkaarttcutts
authored
Add onlyJobState option for SLURM executor (#6659)
Co-authored-by: Chris Hakkaart <[email protected]> Co-authored-by: tcutts <[email protected]>
1 parent d01cbde commit 3c3e9f5

File tree

6 files changed

+99
-1
lines changed

6 files changed

+99
-1
lines changed

docs/executor.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,10 @@ Nextflow does not provide direct support for SLURM multi-clusters. If you need t
446446
Some SLURM clusters require memory allocations to be specified with `--mem-per-cpu` instead of `--mem`. You can specify `executor.perCpuMemAllocation = true` in the Nextflow configuration to enable this behavior. Nextflow will automatically compute the memory per CPU for each task (by default 1 CPU is used).
447447
:::
448448

449+
:::{versionadded} 25.12.0-edge
450+
Since SLURM 24, `squeue` supports an `--only-job-state` option that ignores the partition (`-p`) or user (`-u`) filters. To enable this behavior, specify `executor.$slurm.onlyJobState = true` in your Nextflow configuration. If `SchedulerParameters=enable_job_state_cache` is enabled, you can expect improved Nextflow performance and reduced load on the SLURM controller. See [`enable_job_state_cache`](https://slurm.schedmd.com/slurm.conf.html#OPT_enable_job_state_cache) and [`--only-job-state`](https://slurm.schedmd.com/squeue.html#OPT_only-job-state) for more information.
451+
:::
452+
449453
(tcs-executor)=
450454

451455
## TCS

docs/reference/config.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,13 @@ The following settings are available:
715715
: *Used only by the {ref}`slurm-executor` executor.*
716716
: When `true`, memory allocations for SLURM jobs are specified as `--mem-per-cpu <task.memory / task.cpus>` instead of `--mem <task.memory>`.
717717

718+
`executor.onlyJobState`
719+
: :::{versionadded} 25.12.0-edge
720+
:::
721+
: *Used only by the {ref}`slurm-executor` executor.*
722+
: *Requires SLURM 24.05 or later.*
723+
: When `true`, job status queries use `squeue --only-job-state` without partition (`-p`) or user (`-u`) filters. This can reduce the load on the SLURM controller, especially if your SLURM administrator has enabled `SchedulerParameters=enable_job_state_cache` in your [SLURM configuration](https://slurm.schedmd.com/slurm.conf.html#OPT_enable_job_state_cache). See [`--only-job-state`](https://slurm.schedmd.com/squeue.html#OPT_only-job-state) for more information (default: `false`).
724+
718725
`executor.perJobMemLimit`
719726
: *Used only by the {ref}`lsf-executor` executor.*
720727
: Enables the *per-job* memory limit mode for LSF jobs.

modules/nextflow/src/main/groovy/nextflow/executor/ExecutorConfig.groovy

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ class ExecutorConfig implements ConfigScope {
108108
""")
109109
final boolean perJobMemLimit
110110

111+
@ConfigOption
112+
@Description("""
113+
*Used only by the SLURM executor.*
114+
115+
When `true`, job status queries use `squeue --only-job-state` without partition (`-p`) or user (`-u`) filters. This is required for SLURM installations where `squeue` only accepts the `--only-job-state` option (default: `false`).
116+
""")
117+
final boolean onlyJobState
118+
111119
@ConfigOption
112120
@Description("""
113121
*Used only by the LSF executor.*
@@ -171,6 +179,7 @@ class ExecutorConfig implements ConfigScope {
171179
name = opts.name
172180
perCpuMemAllocation = opts.perCpuMemAllocation as boolean
173181
perJobMemLimit = opts.perJobMemLimit as boolean
182+
onlyJobState = opts.onlyJobState as boolean
174183
perTaskReserve = opts.perTaskReserve as boolean
175184
pollInterval = opts.pollInterval as Duration
176185
queueGlobalStatus = opts.queueGlobalStatus as boolean

modules/nextflow/src/main/groovy/nextflow/executor/SlurmExecutor.groovy

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class SlurmExecutor extends AbstractGridExecutor implements TaskArrayExecutor {
4040
static private Pattern SUBMIT_REGEX = ~/Submitted batch job (\d+)/
4141

4242
private boolean perCpuMemAllocation
43+
private boolean onlyJobState
4344

4445
private boolean hasSignalOpt(TaskConfig config) {
4546
final opts = config.getClusterOptionsAsString()
@@ -157,7 +158,13 @@ class SlurmExecutor extends AbstractGridExecutor implements TaskArrayExecutor {
157158
@Override
158159
protected List<String> queueStatusCommand(Object queue) {
159160

160-
final result = ['squeue','--noheader','-o','%i %t', '-t', 'all']
161+
final result = ['squeue','--noheader', '-o','%i %t', '-t', 'all']
162+
163+
if( onlyJobState ) {
164+
result << '--only-job-state'
165+
// -p and -u cannot be used with --only-job-state
166+
return result
167+
}
161168

162169
if( queue )
163170
result << '-p' << queue.toString()
@@ -213,6 +220,7 @@ class SlurmExecutor extends AbstractGridExecutor implements TaskArrayExecutor {
213220
void register() {
214221
super.register()
215222
perCpuMemAllocation = config.getExecConfigProp(name, 'perCpuMemAllocation', false)
223+
onlyJobState = config.getExecConfigProp(name, 'onlyJobState', false)
216224
}
217225

218226
@Override

modules/nextflow/src/test/groovy/nextflow/executor/ExecutorConfigTest.groovy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,27 @@ class ExecutorConfigTest extends Specification {
116116
config.getExecConfigProp( 'hazelcast', 'jobName', 'alpha', [NXF_EXECUTOR_JOBNAME:'hola']) == 'hola'
117117
}
118118

119+
def 'test onlyJobState property'() {
120+
121+
when:
122+
def config = new ExecutorConfig(['$slurm':[onlyJobState: true] ])
123+
then:
124+
config.getExecConfigProp('slurm', 'onlyJobState', false) == true
125+
config.getExecConfigProp('lsf', 'onlyJobState', false) == false
126+
127+
when:
128+
config = new ExecutorConfig([onlyJobState: true, '$slurm':[onlyJobState: false] ])
129+
then:
130+
config.getExecConfigProp('slurm', 'onlyJobState', false) == false
131+
config.getExecConfigProp('lsf', 'onlyJobState', false) == true
132+
133+
when:
134+
config = new ExecutorConfig([:])
135+
then:
136+
config.getExecConfigProp('slurm', 'onlyJobState', false) == false
137+
config.getExecConfigProp('slurm', 'onlyJobState', true) == false // Property exists and is false, so default is not used
138+
config.getExecConfigProp('slurm', 'nonExistentProp', true) == true // Non-existent property uses default
139+
}
140+
119141

120142
}

modules/nextflow/src/test/groovy/nextflow/executor/SlurmExecutorTest.groovy

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,54 @@ class SlurmExecutorTest extends Specification {
312312
exec.queueStatusCommand('xxx') == ['squeue','--noheader','-o','%i %t','-t','all','-p','xxx','-u', usr]
313313
}
314314

315+
def 'should use onlyJobState option and omit queue and user' () {
316+
given:
317+
def exec = createExecutor()
318+
exec.@onlyJobState = true
319+
320+
when:
321+
def result = exec.queueStatusCommand(null)
322+
323+
then:
324+
result == ['squeue','--noheader','-o','%i %t','-t','all','--only-job-state']
325+
!result.contains('-u')
326+
!result.contains('-p')
327+
}
328+
329+
def 'should use onlyJobState option and ignore queue parameter' () {
330+
given:
331+
def exec = createExecutor()
332+
exec.@onlyJobState = true
333+
334+
when:
335+
def result = exec.queueStatusCommand('myqueue')
336+
337+
then:
338+
result == ['squeue','--noheader','-o','%i %t','-t','all','--only-job-state']
339+
!result.contains('-p')
340+
!result.contains('myqueue')
341+
!result.contains('-u')
342+
}
343+
344+
def 'should include queue and user when onlyJobState is disabled' () {
345+
given:
346+
def exec = createExecutor()
347+
exec.@onlyJobState = false
348+
349+
when:
350+
def usr = System.getProperty('user.name')
351+
def resultNoQueue = exec.queueStatusCommand(null)
352+
def resultWithQueue = exec.queueStatusCommand('myqueue')
353+
354+
then:
355+
resultNoQueue == ['squeue','--noheader','-o','%i %t','-t','all','-u', usr]
356+
!resultNoQueue.contains('--only-job-state')
357+
358+
and:
359+
resultWithQueue == ['squeue','--noheader','-o','%i %t','-t','all','-p','myqueue','-u', usr]
360+
!resultWithQueue.contains('--only-job-state')
361+
}
362+
315363
def 'should get array index name and start' () {
316364
given:
317365
def executor = createExecutor()

0 commit comments

Comments
 (0)