Skip to content

Commit 9b5ef6b

Browse files
authored
[Test] Key exclusive concurrency group on --env-file, not build id (#9949)
Exclusive smoke steps (--exclusive) are serialized via a Buildkite concurrency group. Keying it on BUILDKITE_BUILD_ID only serializes steps within one build, so two exclusive builds targeting the same server (a re-triggered run, or a deploy-and-test command racing a manual run) can run server-mutating tests concurrently and corrupt each other. Key the group on a hash of the --env-file value instead, so all exclusive runs against the same target serialize regardless of which build triggered them. Fall back to the build id when no --env-file is given (each build isolated, as before).
1 parent b86eaf3 commit 9b5ef6b

1 file changed

Lines changed: 14 additions & 8 deletions

File tree

.buildkite/generate_pipeline.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import argparse
2525
import collections
26+
import hashlib
2627
import os
2728
import re
2829
import shlex
@@ -232,8 +233,8 @@ def _parse_args(args: Optional[str] = None):
232233
extra_args.append(f'--generic-cloud {parsed_args.generic_cloud}')
233234

234235
return (default_clouds_to_run, parsed_args.k, extra_args,
235-
parsed_args.concurrency, parsed_args.env_file
236-
is not None, parsed_args.exclusive, pytest_native)
236+
parsed_args.concurrency, parsed_args.env_file,
237+
parsed_args.exclusive, pytest_native)
237238

238239

239240
def _extract_marked_tests(
@@ -380,8 +381,9 @@ def _generate_pipeline(test_file: str, args: str) -> Dict[str, Any]:
380381
"""Generate a Buildkite pipeline from test files."""
381382
steps = []
382383
generated_steps_set = set()
383-
(default_clouds_to_run, k_value, extra_args, concurrency, has_env_file,
384+
(default_clouds_to_run, k_value, extra_args, concurrency, env_file,
384385
exclusive, pytest_native) = _parse_args(args)
386+
has_env_file = env_file is not None
385387
# Pass a clean arg string: extra_args (conftest-registered flags extracted
386388
# from the generate_pipeline parser) + pytest_native (conftest-registered
387389
# flags the generate_pipeline parser did not recognise).
@@ -397,12 +399,16 @@ def _generate_pipeline(test_file: str, args: str) -> Dict[str, Any]:
397399
build_id = None
398400
concurrency_group = None
399401
if exclusive:
400-
# Exclusive tests mutate shared server state, so the whole
401-
# exclusive-only run is serialized to one step at a time, regardless of
402-
# --concurrency / --env-file.
402+
# Exclusive tests mutate shared server state, so the whole exclusive-only
403+
# run is serialized to one step at a time. Key the group on the target
404+
# (the --env-file) rather than the build id, so two exclusive builds
405+
# against the SAME server also serialize -- e.g. a re-triggered run, or a
406+
# deploy-and-test command racing a manual run. Fall back to the build id
407+
# when there is no --env-file (each build kept isolated).
403408
concurrency_limit = 1
404-
build_id = os.environ.get('BUILDKITE_BUILD_ID', 'local')
405-
concurrency_group = f'exclusive-smoke-test-{build_id}'
409+
tag = (hashlib.sha256(env_file.encode()).hexdigest()[:12]
410+
if env_file else os.environ.get('BUILDKITE_BUILD_ID', 'local'))
411+
concurrency_group = f'exclusive-smoke-test-{tag}'
406412
elif has_env_file:
407413
concurrency_limit = (concurrency if concurrency is not None else
408414
DEFAULT_ENV_FILE_CONCURRENCY_LIMIT)

0 commit comments

Comments
 (0)