Skip to content

Commit 2c04d54

Browse files
committed
Enh(batch monitor): Retrieve commands to rerun select instances
1 parent d1a3296 commit 2c04d54

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

codeclash/viewer/app_aws.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def __init__(
3838
self.logs_base_dir = logs_base_dir or Path("logs")
3939
self._job_id_to_folder: dict[str, str] | None = None
4040
self._job_id_to_round_info: dict[str, tuple[int, int] | None] | None = None
41+
self._job_id_to_aws_command: dict[str, str | None] | None = None
4142

4243
def list_jobs(self, *, limit: int | None = None, hours_back: int = 24) -> list[dict[str, Any]]:
4344
"""List all jobs from AWS Batch
@@ -97,6 +98,7 @@ def format_job_for_display(self, job: dict[str, Any]) -> dict[str, Any]:
9798
emagedoc_link = self._generate_emagedoc_link(job_id)
9899
s3_link = self._generate_s3_link(job_id)
99100
round_info = self._get_round_info(job_id)
101+
aws_command = self._get_aws_command(job_id)
100102

101103
return {
102104
"job_id": job_id,
@@ -110,6 +112,7 @@ def format_job_for_display(self, job: dict[str, Any]) -> dict[str, Any]:
110112
"emagedoc_link": emagedoc_link,
111113
"s3_link": s3_link,
112114
"round_info": round_info,
115+
"aws_command": aws_command,
113116
}
114117

115118
def _calculate_time_running(
@@ -150,10 +153,12 @@ def _build_job_id_to_folder_mapping(self) -> dict[str, str]:
150153

151154
mapping = {}
152155
round_info_mapping = {}
156+
aws_command_mapping = {}
153157
if not self.logs_base_dir.exists():
154158
logger.warning(f"Logs directory does not exist: {self.logs_base_dir}")
155159
self._job_id_to_folder = mapping
156160
self._job_id_to_round_info = round_info_mapping
161+
self._job_id_to_aws_command = aws_command_mapping
157162
return mapping
158163

159164
for metadata_file in self.logs_base_dir.rglob("metadata.json"):
@@ -172,11 +177,15 @@ def _build_job_id_to_folder_mapping(self) -> dict[str, str]:
172177
round_info_mapping[job_id] = (completed_rounds, total_rounds)
173178
else:
174179
round_info_mapping[job_id] = None
180+
181+
aws_command = metadata.get("aws", {}).get("AWS_USER_PROVIDED_COMMAND")
182+
aws_command_mapping[job_id] = aws_command
175183
except (json.JSONDecodeError, OSError, KeyError, ValueError) as e:
176184
logger.debug(f"Failed to read metadata from {metadata_file}: {e}")
177185

178186
self._job_id_to_folder = mapping
179187
self._job_id_to_round_info = round_info_mapping
188+
self._job_id_to_aws_command = aws_command_mapping
180189
logger.info(f"Built job ID mapping with {len(mapping)} entries")
181190
return mapping
182191

@@ -186,6 +195,12 @@ def _get_round_info(self, job_id: str) -> tuple[int, int] | None:
186195
self._build_job_id_to_folder_mapping()
187196
return self._job_id_to_round_info.get(job_id) if self._job_id_to_round_info else None
188197

198+
def _get_aws_command(self, job_id: str) -> str | None:
199+
"""Get AWS command for a job"""
200+
if self._job_id_to_aws_command is None:
201+
self._build_job_id_to_folder_mapping()
202+
return self._job_id_to_aws_command.get(job_id) if self._job_id_to_aws_command else None
203+
189204
def _generate_aws_console_link(self, job_id: str) -> str:
190205
"""Generate AWS console link for a job"""
191206
account_id = "039984708918"

codeclash/viewer/templates/batch.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,9 @@ <h2>Bulk Actions</h2>
738738
<button class="modal-action-btn" onclick="fillTextareaWithBatchTerminateCommands()">
739739
<i class="bi bi-stop-circle"></i> AWS Batch terminate
740740
</button>
741+
<button class="modal-action-btn" onclick="fillTextareaWithAWSResubmitCommands()">
742+
<i class="bi bi-arrow-repeat"></i> AWS resubmit commands
743+
</button>
741744
</div>
742745
<div id="modal-warning" class="modal-warning">
743746
<i class="bi bi-exclamation-triangle"></i>
@@ -1214,6 +1217,32 @@ <h2>Bulk Actions</h2>
12141217
document.getElementById('bulk-actions-textarea').value = commands.join('\n');
12151218
}
12161219

1220+
function fillTextareaWithAWSResubmitCommands() {
1221+
if (selectedJobs.size === 0) {
1222+
showModalWarning('No jobs selected. Please select jobs from the table first.');
1223+
document.getElementById('bulk-actions-textarea').value = '';
1224+
return;
1225+
}
1226+
1227+
const selectedJobsList = Array.from(selectedJobs);
1228+
const jobsWithCommand = selectedJobsList
1229+
.map(jobId => allJobs.find(job => job.job_id === jobId))
1230+
.filter(job => job && job.aws_command);
1231+
1232+
if (jobsWithCommand.length === 0) {
1233+
showModalWarning('None of the selected jobs have AWS command information available.');
1234+
document.getElementById('bulk-actions-textarea').value = '';
1235+
return;
1236+
}
1237+
1238+
const commands = jobsWithCommand.map(job => {
1239+
return `aws/run_job.py -- ${job.aws_command}`;
1240+
});
1241+
1242+
hideModalWarning();
1243+
document.getElementById('bulk-actions-textarea').value = commands.join('\n');
1244+
}
1245+
12171246
function copyFromModal() {
12181247
const textarea = document.getElementById('bulk-actions-textarea');
12191248
const text = textarea.value;

0 commit comments

Comments
 (0)