Avaiga / taipy

Turns Data and AI algorithms into production-ready web applications in no time.
https://www.taipy.io
Apache License 2.0
12.65k stars 952 forks source link

Scenario - callback on Scenario submission status change #211

Closed FabienLelaquais closed 1 year ago

FabienLelaquais commented 1 year ago

When a scenario is submitted, we want the application to be notified when its status changes. This allows for providing visual feedback on what is going on.

The minimum would be Running and Completed.

jrobinAV commented 1 year ago

We need to be precise and careful about this. Submitting a scenario consists in creating and running a bunch of jobs (potentially a few tens). There is no status attached to a Scenario. Statuses are attached to jobs. We don't want to notify the user for each job created/running/completed.

So we need to define what it means a running scenario status or a completed scenario status.

FlorianJacta commented 1 year ago

We should also know it in the GUI so that related visual elements refresh when the scenario is 'completed'. Maybe, it is more than this issue suggests. I can create an issue on this!

jrobinAV commented 1 year ago

Based on a discussion we had:

Context

In the future, Core should provide a Submission entity that should hold information related to submission, particularly the related entities (list of jobs, submittable) and a new status (compiled from the job statuses). Since taipy-core has not yet provided the Submission entity, here is a proposal to implement in taipy.

Callback proposal

The idea is to add an on_submission_change callback on the scenario viewer. Taipy will monitor Core notifications (at the Jobs level) and interpret these notifications to create a high-level object that the user can receive in this callback. The callback should be triggered when there is a change in one of the job entities related to the submission. The proposal's goal is to ensure that the API we would offer in version 3.0 remains stable in the future.

def on_submission_change(state, submittable: [Submittable], details: dict)

The details dictionary (Renamed from status to details to avoid confusion. What do you think?) would contain high and low-level information about what has happened. In particular, it should contain the submission status compiled from the various job statuses.

So, until Core provides a Submission Entity, Core Elements would link a submission_id to the submittable entity and manage the list of jobs. Event monitoring would be set up when a user triggers the submission themselves. At that point, we can send these events to the user, and no one else.

If, in the future, we have higher-level events (like a Submission change event), we would have a new 'submission' key with the future Submission entity provided by Core, and no 'job', no job_status, and no submission status.

Examples

Here is an example of the details dict for 3.0 version:

{
   "submission_status": "submitted" or "running" or "completed" or "blocked",
   "job": Job,
   "job_status": "submitted" or "running" or "completed" or "blocked",
   "information": "..." # whatever it may be
}

In the example above, the submission status is created by GuiCore based on all the job statuses.

Here is an example of the details dict for 3.X version:

{
   "submission": Submission,
   "information": "..." # whatever it may be
}

In the example above, the submission is provided by Core and could directly contain the submission status.

Submission statuses

Here is the submission status proposal:

SUBMITTED: All the jobs are submitted. COMPLETED: All jobs are completed or skipped. CANCELED: At least one job has a canceled status. FAILED: At least one job has a failed status. BLOCKED: All the jobs are (blocked or completed or skipped) and at least one has a blocked status. WAITING: All the jobs are pending or blocked and at least one has pending status. RUNNING: There is no canceled job, no failed job, no abandoned job, and at least one job has a running status. UNDEFINED: else

FredLL-Avaiga commented 1 year ago

@jrobinAV What is the submission status if it has one abandoned Job ?

FredLL-Avaiga commented 1 year ago

Here is my implementation of the submission status: please review

    def _get_submittable_status(self, jobs_ids: t.List[str]):
        status = _SubmissionStatus.UNDEFINED
        blocked = False
        waiting = False
        running = False
        completed = False
        for id in jobs_ids:
            job = core_get(id)
            if not job:
                continue
            if job.is_failed():
                status = _SubmissionStatus.FAILED
                break
            if job.is_canceled():
                status = _SubmissionStatus.CANCELED
                break
            if not blocked and job.is_blocked():
                blocked = True
            if not waiting and job.is_pending():
                waiting = True
            if not running and job.is_running():
                running = True
            if not completed and (job.is_completed() or job.is_skipped()):
                completed = True
        if status is _SubmissionStatus.UNDEFINED:
            if waiting:
                status = _SubmissionStatus.WAITING
            elif blocked:
                status = _SubmissionStatus.BLOCKED
            elif running:
                status = _SubmissionStatus.RUNNING
            elif completed:
                status = _SubmissionStatus.COMPLETED
        return status
jrobinAV commented 1 year ago

@jrobinAV What is the submission status if it has one abandoned Job ? IF there is an abandoned Job, that means there is at least a canceled job in the list of jobs. So the Submission status is canceled

jrobinAV commented 1 year ago

Here is my implementation of the submission status: please review

    def _get_submittable_status(self, jobs_ids: t.List[str]):
        status = _SubmissionStatus.UNDEFINED
        blocked = False
        waiting = False
        running = False
        completed = False
        for id in jobs_ids:
            job = core_get(id)
            if not job:
                continue
            if job.is_failed():
                status = _SubmissionStatus.FAILED
                break
            if job.is_canceled():
                status = _SubmissionStatus.CANCELED
                break
            if not blocked and job.is_blocked():
                blocked = True
            if not waiting and job.is_pending():
                waiting = True
            if not running and job.is_running():
                running = True
            if not completed and (job.is_completed() or job.is_skipped()):
                completed = True
        if status is _SubmissionStatus.UNDEFINED:
            if waiting:
                status = _SubmissionStatus.WAITING
            elif blocked:
                status = _SubmissionStatus.BLOCKED
            elif running:
                status = _SubmissionStatus.RUNNING
            elif completed:
                status = _SubmissionStatus.COMPLETED
        return status

It looks good to me, but some unit tests would give more guarantees it is working.