@@ -1128,18 +1128,25 @@ def _launch_containers(
11281128 if raw :
11291129 extra_volumes = [v .strip () for v in raw .split ("," ) if v .strip ()]
11301130
1131- runnable = container_command_to_gcp_runnable ("pulsar-container" , pulsar_submit_container )
1132- if extra_volumes :
1133- runnable .container .volumes = extra_volumes
1134- job .task_groups [0 ].task_spec .runnables .append (runnable )
1135-
1131+ # Order matters: GCP Batch runs runnables sequentially. A background
1132+ # runnable starts and immediately yields to the next runnable. We need:
1133+ # 1. Tool (background) — starts polling for command_line file
1134+ # 2. Sidecar (foreground) — stages inputs, writes command_line, polls
1135+ # for return_code, collects outputs, sends AMQP callback
1136+ # The sidecar must be foreground so it survives after the tool finishes
1137+ # (GCP Batch kills background runnables when all foreground ones exit).
11361138 if tool_container :
11371139 tool_runnable = container_command_to_gcp_runnable ("tool-container" , tool_container )
11381140 tool_runnable .background = True
11391141 if extra_volumes :
11401142 tool_runnable .container .volumes = extra_volumes
11411143 job .task_groups [0 ].task_spec .runnables .append (tool_runnable )
11421144
1145+ runnable = container_command_to_gcp_runnable ("pulsar-container" , pulsar_submit_container )
1146+ if extra_volumes :
1147+ runnable .container .volumes = extra_volumes
1148+ job .task_groups [0 ].task_spec .runnables .append (runnable )
1149+
11431150 job_name = self ._job_name
11441151 create_request = gcp_job_request (gcp_job_params , job , job_name )
11451152 client = gcp_client (gcp_job_params .credentials_file )
0 commit comments