Skip to content

Commit

Permalink
[FLorist] Job progress (#94)
Browse files Browse the repository at this point in the history
Clickup Ticket(s): https://app.clickup.com/t/8689q5t5r

Adding progress bar and metrics to job details page.

Additionally, changing the metrics listener to update the metrics every time it changes so we can see the changes in the page.
  • Loading branch information
lotif authored Sep 25, 2024
1 parent 80675e0 commit bdb5369
Show file tree
Hide file tree
Showing 6 changed files with 657 additions and 22 deletions.
2 changes: 1 addition & 1 deletion florist/api/db/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,5 @@ def assert_updated_successfully(update_result: UpdateResult) -> None:
raw_result = update_result.raw_result
assert isinstance(raw_result, dict)
assert raw_result["n"] == 1, f"UpdateResult's 'n' is not 1 ({update_result})"
assert raw_result["nModified"] == 1, f"UpdateResult's 'nModified' is not 1 ({update_result})"
assert raw_result["nModified"] in [1, 0], f"UpdateResult's 'nModified' is not 1 or 0 ({update_result})"
assert raw_result["ok"] == 1, f"UpdateResult's 'ok' is not 1 ({update_result})"
42 changes: 29 additions & 13 deletions florist/api/routes/server/training.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ def server_training_listener(job: Job, database: Database[Dict[str, Any]]) -> No
# check if training has already finished before start listening
server_metrics = get_from_redis(job.server_uuid, job.redis_host, job.redis_port)
LOGGER.debug(f"Listener: Current metrics for job {job.id}: {server_metrics}")
if server_metrics is not None and "fit_end" in server_metrics:
close_job(job, server_metrics, database)
return
if server_metrics is not None:
update_job_metrics(job, server_metrics, database)
if "fit_end" in server_metrics:
close_job(job, database)
return

subscriber = get_subscriber(job.server_uuid, job.redis_host, job.redis_port)
# TODO add a max retries mechanism, maybe?
Expand All @@ -158,25 +160,26 @@ def server_training_listener(job: Job, database: Database[Dict[str, Any]]) -> No
server_metrics = get_from_redis(job.server_uuid, job.redis_host, job.redis_port)
LOGGER.debug(f"Listener: Message received for job {job.id}. Metrics: {server_metrics}")

if server_metrics is not None and "fit_end" in server_metrics:
close_job(job, server_metrics, database)
return
if server_metrics is not None:
update_job_metrics(job, server_metrics, database)
if "fit_end" in server_metrics:
close_job(job, database)
return


def close_job(job: Job, server_metrics: Dict[str, Any], database: Database[Dict[str, Any]]) -> None:
def update_job_metrics(job: Job, server_metrics: Dict[str, Any], database: Database[Dict[str, Any]]) -> None:
"""
Close the job.
Update the job with server and client metrics.
Collect the job's clients metrics, saving them and the server's metrics to the job and marking its
status as FINISHED_SUCCESSFULLY.
Collect the job's clients metrics, saving them and the server's metrics to the job.
:param job: (Job) The job to be closed.
:param job: (Job) The job to be updated.
:param server_metrics: (Dict[str, Any]) The server's metrics to be saved into the job.
:param database: (pymongo.database.Database) An instance of the database to save the information
into the Job. MUST BE A SYNCHRONOUS DATABASE since this function cannot be marked as async
because of limitations with FastAPI's BackgroundTasks.
"""
LOGGER.info(f"Listener: Training finished for job {job.id}")
LOGGER.info(f"Listener: Updating metrics for job {job.id}")

clients_metrics: List[Dict[str, Any]] = []
if job.clients_info is not None:
Expand All @@ -191,7 +194,20 @@ def close_job(job: Job, server_metrics: Dict[str, Any], database: Database[Dict[
client_metrics = response.json()
clients_metrics.append(client_metrics)

job.set_status_sync(JobStatus.FINISHED_SUCCESSFULLY, database)
job.set_metrics(server_metrics, clients_metrics, database)

LOGGER.info(f"Listener: Job {job.id} has been updated.")


def close_job(job: Job, database: Database[Dict[str, Any]]) -> None:
"""
Close the job by marking its status as FINISHED_SUCCESSFULLY.
:param job: (Job) The job to be closed.
:param database: (pymongo.database.Database) An instance of the database to save the information
into the Job. MUST BE A SYNCHRONOUS DATABASE since this function cannot be marked as async
because of limitations with FastAPI's BackgroundTasks.
"""
LOGGER.info(f"Listener: Training finished for job {job.id}")
job.set_status_sync(JobStatus.FINISHED_SUCCESSFULLY, database)
LOGGER.info(f"Listener: Job {job.id} status has been set to {job.status.value}.")
27 changes: 27 additions & 0 deletions florist/app/assets/css/florist.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,30 @@
border-radius: 5px;
color: white;
}

#job-progress .progress {
padding: 0;
margin: 0 12px;
height: max-content;
}

#job-progress .progress-bar {
height: 25px;
}

#job-progress .progress-bar.bg-disabled {
background-color: lightgray !important;
}

.job-expand-button a.btn {
padding: 0;
margin: 0;
}

.job-round-details {
padding-left: 40px;
}

.job-round-details .col-sm-2 {
width: 20%;
}
Loading

0 comments on commit bdb5369

Please sign in to comment.