|
@@ -9,13 +9,17 @@
|
|
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations under the License.
|
|
# specific language governing permissions and limitations under the License.
|
|
|
|
|
|
|
|
+from threading import Lock
|
|
from typing import List, Optional, Union
|
|
from typing import List, Optional, Union
|
|
|
|
|
|
|
|
+from taipy.logger._taipy_logger import _TaipyLogger
|
|
|
|
+
|
|
from .._entity._entity_ids import _EntityIds
|
|
from .._entity._entity_ids import _EntityIds
|
|
from .._manager._manager import _Manager
|
|
from .._manager._manager import _Manager
|
|
from .._repository._abstract_repository import _AbstractRepository
|
|
from .._repository._abstract_repository import _AbstractRepository
|
|
from .._version._version_mixin import _VersionMixin
|
|
from .._version._version_mixin import _VersionMixin
|
|
from ..exceptions.exceptions import SubmissionNotDeletedException
|
|
from ..exceptions.exceptions import SubmissionNotDeletedException
|
|
|
|
+from ..job.job import Job, Status
|
|
from ..notification import EventEntityType, EventOperation, Notifier, _make_event
|
|
from ..notification import EventEntityType, EventOperation, Notifier, _make_event
|
|
from ..scenario.scenario import Scenario
|
|
from ..scenario.scenario import Scenario
|
|
from ..sequence.sequence import Sequence
|
|
from ..sequence.sequence import Sequence
|
|
@@ -27,6 +31,8 @@ class _SubmissionManager(_Manager[Submission], _VersionMixin):
|
|
_ENTITY_NAME = Submission.__name__
|
|
_ENTITY_NAME = Submission.__name__
|
|
_repository: _AbstractRepository
|
|
_repository: _AbstractRepository
|
|
_EVENT_ENTITY_TYPE = EventEntityType.SUBMISSION
|
|
_EVENT_ENTITY_TYPE = EventEntityType.SUBMISSION
|
|
|
|
+ __lock = Lock()
|
|
|
|
+ __logger = _TaipyLogger._get_logger()
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
def _get_all(cls, version_number: Optional[str] = None) -> List[Submission]:
|
|
def _get_all(cls, version_number: Optional[str] = None) -> List[Submission]:
|
|
@@ -47,6 +53,88 @@ class _SubmissionManager(_Manager[Submission], _VersionMixin):
|
|
|
|
|
|
return submission
|
|
return submission
|
|
|
|
|
|
|
|
+ @classmethod
|
|
|
|
+ def _update_submission_status(cls, submission: Submission, job: Job):
|
|
|
|
+ with cls.__lock:
|
|
|
|
+ submission = cls._get(submission)
|
|
|
|
+
|
|
|
|
+ if submission._submission_status == SubmissionStatus.FAILED:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ job_status = job.status
|
|
|
|
+ if job_status == Status.FAILED:
|
|
|
|
+ submission._submission_status = SubmissionStatus.FAILED
|
|
|
|
+ cls._set(submission)
|
|
|
|
+ cls.__logger.debug(
|
|
|
|
+ f"{job.id} status is {job_status}. Submission status set to `{submission._submission_status}`."
|
|
|
|
+ )
|
|
|
|
+ return
|
|
|
|
+ if job_status == Status.CANCELED:
|
|
|
|
+ submission._is_canceled = True
|
|
|
|
+ elif job_status == Status.BLOCKED:
|
|
|
|
+ submission._blocked_jobs.add(job.id)
|
|
|
|
+ submission._pending_jobs.discard(job.id)
|
|
|
|
+ elif job_status == Status.PENDING or job_status == Status.SUBMITTED:
|
|
|
|
+ submission._pending_jobs.add(job.id)
|
|
|
|
+ submission._blocked_jobs.discard(job.id)
|
|
|
|
+ elif job_status == Status.RUNNING:
|
|
|
|
+ submission._running_jobs.add(job.id)
|
|
|
|
+ submission._pending_jobs.discard(job.id)
|
|
|
|
+ elif job_status == Status.COMPLETED or job_status == Status.SKIPPED:
|
|
|
|
+ submission._is_completed = True # type: ignore
|
|
|
|
+ submission._blocked_jobs.discard(job.id)
|
|
|
|
+ submission._pending_jobs.discard(job.id)
|
|
|
|
+ submission._running_jobs.discard(job.id)
|
|
|
|
+ elif job_status == Status.ABANDONED:
|
|
|
|
+ submission._is_abandoned = True # type: ignore
|
|
|
|
+ submission._running_jobs.discard(job.id)
|
|
|
|
+ submission._blocked_jobs.discard(job.id)
|
|
|
|
+ submission._pending_jobs.discard(job.id)
|
|
|
|
+ cls._set(submission)
|
|
|
|
+
|
|
|
|
+ # The submission_status is set later to make sure notification for updating
|
|
|
|
+ # the submission_status attribute is triggered
|
|
|
|
+ if submission._is_canceled:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.CANCELED, job)
|
|
|
|
+ elif submission._is_abandoned:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.UNDEFINED, job)
|
|
|
|
+ elif submission._running_jobs:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.RUNNING, job)
|
|
|
|
+ elif submission._pending_jobs:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.PENDING, job)
|
|
|
|
+ elif submission._blocked_jobs:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.BLOCKED, job)
|
|
|
|
+ elif submission._is_completed:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.COMPLETED, job)
|
|
|
|
+ else:
|
|
|
|
+ cls._set_submission_status(submission, SubmissionStatus.UNDEFINED, job)
|
|
|
|
+ cls.__logger.debug(
|
|
|
|
+ f"{job.id} status is {job_status}. Submission status set to `{submission._submission_status}`"
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ @classmethod
|
|
|
|
+ def _set_submission_status(cls, submission: Submission, new_submission_status: SubmissionStatus, job: Job):
|
|
|
|
+ if not submission._is_in_context:
|
|
|
|
+ submission = cls._get(submission)
|
|
|
|
+ _current_submission_status = submission._submission_status
|
|
|
|
+ submission._submission_status = new_submission_status
|
|
|
|
+
|
|
|
|
+ cls._set(submission)
|
|
|
|
+
|
|
|
|
+ if _current_submission_status != submission._submission_status:
|
|
|
|
+ event = _make_event(
|
|
|
|
+ submission,
|
|
|
|
+ EventOperation.UPDATE,
|
|
|
|
+ "submission_status",
|
|
|
|
+ submission._submission_status,
|
|
|
|
+ job_triggered_submission_status_changed=job.id,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ if not submission._is_in_context:
|
|
|
|
+ Notifier.publish(event)
|
|
|
|
+ else:
|
|
|
|
+ submission._in_context_attributes_changed_collector.append(event)
|
|
|
|
+
|
|
@classmethod
|
|
@classmethod
|
|
def _get_latest(cls, entity: Union[Scenario, Sequence, Task]) -> Optional[Submission]:
|
|
def _get_latest(cls, entity: Union[Scenario, Sequence, Task]) -> Optional[Submission]:
|
|
entity_id = entity.id if not isinstance(entity, str) else entity
|
|
entity_id = entity.id if not isinstance(entity, str) else entity
|