Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit bc4a47d

Browse files
committed
Enhanced support for autogen task ids
- Add support to override global default at a per-job level and at a per task factory level - Resolves #324
1 parent b0a3b9e commit bc4a47d

File tree

7 files changed

+106
-31
lines changed

7 files changed

+106
-31
lines changed

config_templates/jobs.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ job_specifications:
6767
default_working_dir: batch
6868
restrict_default_bind_mounts: false
6969
force_enable_task_dependencies: false
70+
autogenerated_task_id:
71+
prefix: task-
72+
zfill_width: 5
7073
federation_constraints:
7174
pool:
7275
autoscale:
@@ -180,6 +183,9 @@ job_specifications:
180183
module: mypkg.mymodule
181184
package: null
182185
repeat: 3
186+
autogenerated_task_id:
187+
prefix: task-
188+
zfill_width: 5
183189
singularity_execution:
184190
cmd: exec
185191
elevated: false

convoy/batch.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4172,16 +4172,17 @@ def _format_generic_task_id(prefix, padding, tasknum):
41724172

41734173

41744174
def _generate_next_generic_task_id(
4175-
batch_client, config, job_id, tasklist=None, reserved=None,
4175+
batch_client, config, job_id, task, tasklist=None, reserved=None,
41764176
task_map=None, last_task_id=None, is_merge_task=False,
41774177
federation_id=None):
41784178
# type: (azure.batch.batch_service_client.BatchServiceClient, dict, str,
4179-
# list, str, dict, str, bool, str) -> Tuple[list, str]
4179+
# dict, list, str, dict, str, bool, str) -> Tuple[list, str]
41804180
"""Generate the next generic task id
41814181
:param batch_client: The batch client to use.
41824182
:type batch_client: `azure.batch.batch_service_client.BatchServiceClient`
41834183
:param dict config: configuration dict
41844184
:param str job_id: job id
4185+
:param dict task: task config spec
41854186
:param list tasklist: list of current (committed) tasks in job
41864187
:param str reserved: reserved task id
41874188
:param dict task_map: map of pending tasks to add to the job
@@ -4192,13 +4193,17 @@ def _generate_next_generic_task_id(
41924193
:return: (list of committed task ids for job, next generic docker task id)
41934194
"""
41944195
# get prefix and padding settings
4195-
prefix = settings.autogenerated_task_id_prefix(config)
4196-
padding = settings.autogenerated_task_id_zfill(config)
4196+
prefix = task['##task_id_prefix']
4197+
padding = task['##task_id_padding']
41974198
delimiter = prefix if util.is_not_empty(prefix) else ' '
41984199
if is_merge_task:
41994200
prefix = 'merge-{}'.format(prefix)
4200-
# get filtered, sorted list of generic docker task ids
4201+
# reset tasklist if cached tasklist doesn't start with prefix
4202+
if (util.is_not_empty(tasklist) and
4203+
not tasklist[0].id.startswith(prefix)):
4204+
tasklist = None
42014205
try:
4206+
# get filtered, sorted list of generic task ids
42024207
if tasklist is None and util.is_none_or_empty(federation_id):
42034208
tasklist = batch_client.task.list(
42044209
job_id,
@@ -4207,6 +4212,7 @@ def _generate_next_generic_task_id(
42074212
if util.is_not_empty(prefix) else None,
42084213
select='id'))
42094214
tasklist = list(tasklist)
4215+
# get last task and increment
42104216
tasknum = sorted(
42114217
[int(x.id.split(delimiter)[-1]) for x in tasklist])[-1] + 1
42124218
except (batchmodels.BatchErrorException, IndexError, TypeError):
@@ -4524,7 +4530,7 @@ def _construct_task(
45244530
_task_id = settings.task_id(_task)
45254531
if util.is_none_or_empty(_task_id):
45264532
existing_tasklist, _task_id = _generate_next_generic_task_id(
4527-
batch_client, config, job_id, tasklist=existing_tasklist,
4533+
batch_client, config, job_id, _task, tasklist=existing_tasklist,
45284534
reserved=reserved_task_id, task_map=task_map,
45294535
last_task_id=lasttaskid, is_merge_task=is_merge_task,
45304536
federation_id=federation_id)
@@ -5198,7 +5204,7 @@ def add_jobs(
51985204
existing_tasklist, reserved_task_id = \
51995205
_generate_next_generic_task_id(
52005206
batch_client, config, job_id,
5201-
tasklist=existing_tasklist,
5207+
task, tasklist=existing_tasklist,
52025208
federation_id=federation_id)
52035209
settings.set_task_id(task, reserved_task_id)
52045210
_id = '{}-{}'.format(job_id, reserved_task_id)
@@ -5846,6 +5852,8 @@ def generate_info_metadata_for_federation_message(
58465852
multi_instance, uses_task_dependencies, has_gpu_task, has_ib_task,
58475853
max_instance_count_in_job, instances_required_in_job, has_merge_task,
58485854
merge_task_id, task_map):
5855+
prefix, padding = settings.autogenerated_task_id_settings(
5856+
config, level='global')
58495857
info = {
58505858
'version': '1',
58515859
'action': {
@@ -5910,8 +5918,8 @@ def generate_info_metadata_for_federation_message(
59105918
},
59115919
},
59125920
'task_naming': {
5913-
'prefix': settings.autogenerated_task_id_prefix(config),
5914-
'padding': settings.autogenerated_task_id_zfill(config),
5921+
'prefix': prefix,
5922+
'padding': padding,
59155923
},
59165924
},
59175925
}

convoy/settings.py

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3089,37 +3089,33 @@ def job_specifications(config):
30893089
'jobs configuration file?')
30903090

30913091

3092-
def autogenerated_task_id_prefix(config):
3093-
# type: (dict) -> str
3092+
def autogenerated_task_id_settings(config, level=None):
3093+
# type: (dict, str) -> Tuple[str, str]
30943094
"""Get the autogenerated task id prefix to use
30953095
:param dict config: configuration object
3096-
:rtype: str
3097-
:return: auto-gen task id prefix
3098-
"""
3099-
conf = _kv_read_checked(
3100-
config['batch_shipyard'], 'autogenerated_task_id', {}
3101-
)
3096+
:param str level: 'global', 'job', or 'task_factory'
3097+
:rtype: tuple
3098+
:return: (auto-gen task id prefix, auto-gen task id zfill)
3099+
"""
3100+
if level == 'global':
3101+
conf = config['batch_shipyard']
3102+
elif level == 'job':
3103+
conf = config
3104+
elif level == 'task_factory':
3105+
conf = config['task_factory']
3106+
else:
3107+
raise RuntimeError(
3108+
'invalid level={} for autogenerated task id setting'.format(level))
3109+
conf = _kv_read_checked(conf, 'autogenerated_task_id', {})
31023110
# do not use _kv_read_checked for prefix we want to allow empty string
31033111
try:
31043112
prefix = conf['prefix']
31053113
if prefix is None:
31063114
raise KeyError()
31073115
except KeyError:
31083116
prefix = 'task-'
3109-
return prefix
3110-
3111-
3112-
def autogenerated_task_id_zfill(config):
3113-
# type: (dict) -> int
3114-
"""Get the autogenerated task zfill setting to use
3115-
:param dict config: configuration object
3116-
:rtype: int
3117-
:return: auto-gen task number zfill
3118-
"""
3119-
conf = _kv_read_checked(
3120-
config['batch_shipyard'], 'autogenerated_task_id', {}
3121-
)
3122-
return _kv_read(conf, 'zfill_width', 5)
3117+
padding = _kv_read(conf, 'zfill_width', 5)
3118+
return (prefix, padding)
31233119

31243120

31253121
def job_tasks(config, conf):
@@ -3130,6 +3126,11 @@ def job_tasks(config, conf):
31303126
:rtype: list
31313127
:return: list of tasks
31323128
"""
3129+
if 'autogenerated_task_id' in conf:
3130+
prefix, padding = autogenerated_task_id_settings(conf, level='job')
3131+
else:
3132+
prefix, padding = autogenerated_task_id_settings(
3133+
config, level='global')
31333134
for _task in conf['tasks']:
31343135
if 'task_factory' in _task:
31353136
# get storage settings if applicable
@@ -3148,10 +3149,21 @@ def job_tasks(config, conf):
31483149
)
31493150
else:
31503151
tfstorage = None
3152+
# get autogenerated task id settings
3153+
if 'autogenerated_task_id' in _task['task_factory']:
3154+
tfprefix, tfpadding = autogenerated_task_id_settings(
3155+
_task, level='task_factory')
3156+
else:
3157+
tfprefix = prefix
3158+
tfpadding = padding
31513159
for task in task_factory.generate_task(_task, tfstorage):
31523160
task['##tfgen'] = True
3161+
task['##task_id_prefix'] = tfprefix
3162+
task['##task_id_padding'] = tfpadding
31533163
yield task
31543164
else:
3165+
_task['##task_id_prefix'] = prefix
3166+
_task['##task_id_padding'] = padding
31553167
yield _task
31563168

31573169

convoy/task_factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,5 +458,7 @@ def generate_task(task, storage_settings):
458458
yield taskcopy
459459
else:
460460
raise ValueError('unknown parametric sweep type: {}'.format(sweep))
461+
elif 'autogenerated_task_id' in task_factory:
462+
pass
461463
else:
462464
raise ValueError('unknown task factory type: {}'.format(task_factory))

docs/14-batch-shipyard-configuration-jobs.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ job_specifications:
9393
default_working_dir: batch
9494
restrict_default_bind_mounts: false
9595
force_enable_task_dependencies: false
96+
autogenerated_task_id:
97+
prefix: task-
98+
zfill_width: 5
9699
federation_constraints:
97100
pool:
98101
autoscale:
@@ -204,6 +207,9 @@ job_specifications:
204207
module: mypkg.mymodule
205208
package: null
206209
repeat: 3
210+
autogenerated_task_id:
211+
prefix: task-
212+
zfill_width: 5
207213
singularity_execution:
208214
cmd: exec
209215
elevated: false
@@ -572,6 +578,18 @@ task dependencies explicitly even if no `tasks` have dependencies specified.
572578
This is useful for scenarios where the same job is used for tasks at a
573579
later time that do have dependencies and/or are dependent on tasks
574580
previously added to the same job. The default is `false`.
581+
* (optional) `autogenerated_task_id` controls how autogenerated task ids
582+
are named. Note that the total length of an autogenerated task id must not
583+
exceed 64 characters. The property specified at this level will overwrite
584+
the "global" setting in the Global configuration file.
585+
* (optional) `prefix` is the task prefix to use with the task id. This can
586+
be any combination of alphanumeric characters including hyphens and
587+
underscores. Empty string is permitted for the `prefix`. The default
588+
is `task-`.
589+
* (optional) `zfill_width` is the number of zeros to left pad the integral
590+
task number. This can be set to zero which may be useful for task
591+
dependency range scenarios in combination with an empty string `prefix`
592+
above. The default is `5`.
575593
* (optional) `federation_constraints` defines properties to apply to the job
576594
and all tasks (i.e., the task group) when submitting the job to a federation.
577595
Please see the [federation guide](68-batch-shipyard-federation.md) for more
@@ -835,6 +853,19 @@ task executions.
835853
`generate` generator function. This should be a dictionary where
836854
all keys are strings.
837855
* (optional) `repeat` will create N number of identical tasks.
856+
* (optional) `autogenerated_task_id` controls how autogenerated task ids
857+
are named for tasks of this task factory only. Note that the total length
858+
of an autogenerated task id must not exceed 64 characters. The property
859+
specified at this level will overwrite both the "global" setting in the
860+
Global configuration file and at the job level.
861+
* (optional) `prefix` is the task prefix to use with the task id.
862+
This can be any combination of alphanumeric characters including
863+
hyphens and underscores. Empty string is permitted for the `prefix`.
864+
The default is `task-`.
865+
* (optional) `zfill_width` is the number of zeros to left pad the
866+
integral task number. This can be set to zero which may be useful
867+
for task dependency range scenarios in combination with an empty
868+
string `prefix` above. The default is `5`.
838869
* (optional) `depends_on` is an array of task ids for which this container
839870
invocation (task) depends on and must run to successful completion prior
840871
to this task executing. Note that when a `task_factory` is specified, all

docs/68-batch-shipyard-federation.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ formula will scale up/down both low priority and dedicated nodes.
313313
federation. Adding a pool to multiple federations simultaneously will result
314314
in undefined behavior.
315315
* Singularity containers are not fully supported in federations.
316+
* Auto-genereated task id configuration at the job and task factory level
317+
are not supported.
316318

317319
### Quotas
318320
Ensure that you have sufficient active job/job schedule quota for each

schemas/jobs.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ mapping:
173173
type: bool
174174
force_enable_task_dependencies:
175175
type: bool
176+
autogenerated_task_id:
177+
type: map
178+
mapping:
179+
prefix:
180+
type: str
181+
zfill_width:
182+
type: int
176183
federation_constraints:
177184
type: map
178185
mapping:
@@ -439,6 +446,13 @@ mapping:
439446
type: str
440447
repeat:
441448
type: int
449+
autogenerated_task_id:
450+
type: map
451+
mapping:
452+
prefix:
453+
type: str
454+
zfill_width:
455+
type: int
442456
id:
443457
type: str
444458
docker_image:

0 commit comments

Comments
 (0)