def test_delete_all(client_fixture: fixture) -> None: page = client_fixture.get(f"/api/delete") assert page.json == {"message": "Scheduler: all jobs deleted!"} assert page.status_code == 200 # one maintenance job should be left assert len(atlas_scheduler.get_jobs()) == 0 # add a job with no args from .conftest import demo_task atlas_scheduler.add_job( func=demo_task, trigger="interval", seconds=10, id="test job 2", name="test job 2", replace_existing=True, ) # add a job and try again p_id, t_id = create_demo_task() page = client_fixture.get(f"/api/add/{t_id}") assert page.json == {"message": "Scheduler: task job added!"} assert page.status_code == 200 page = client_fixture.get(f"/api/delete") assert page.json == {"message": "Scheduler: all jobs deleted!"} assert page.status_code == 200 # one job should be left assert len(atlas_scheduler.get_jobs()) == 1
def delete_all_tasks() -> Response: """Delete all scheduled tasks.""" for job in atlas_scheduler.get_jobs(): if re.match(r"^\d+-\d+-.+?$", job.id): job.remove() return jsonify({"message": "Scheduler: all jobs deleted!"})
def delete_orphans() -> Response: """Delete all orphaned jobs.""" for job in atlas_scheduler.get_jobs(): if job.args and Task.query.filter_by(id=int(job.args[0])).count() == 0: job.remove() return jsonify({"message": "Scheduler: orphans deleted!"})
def get_jobs_details() -> Response: """Get list of all jobs with all details.""" return jsonify([{ "name": job.name, "job_id": job.id, "next_run_time": job.next_run_time, "id": job.id.split("-")[1], } for job in atlas_scheduler.get_jobs() if re.match(r"^\d+-\d+-.+?$", job.id)])
def test_delete_orphans(client_fixture: fixture) -> None: # run without any orphans page = client_fixture.get(f"/api/delete-orphans") assert page.json == {"message": "Scheduler: orphans deleted!"} assert page.status_code == 200 # manually add a job to scheduler atlas_scheduler.add_job( func=demo_task, trigger="interval", seconds=10, id="test job 2", name="test job 2", args=["99"], replace_existing=True, ) assert len(atlas_scheduler.get_jobs()) == 1 # job with no args atlas_scheduler.add_job( func=demo_task, trigger="interval", seconds=10, id="test job 3", name="test job 3", replace_existing=True, ) assert len(atlas_scheduler.get_jobs()) == 2 page = client_fixture.get(f"/api/delete-orphans") assert page.json == {"message": "Scheduler: orphans deleted!"} assert page.status_code == 200 assert len(atlas_scheduler.get_jobs()) == 1
def scheduler_delete_task(task_id: int) -> bool: """Delete all jobs associated with a task from the scheduler. :param task_id: id of task to delete associated jobs :returns: true """ status = False for job in atlas_scheduler.get_jobs(): if job.args and str(job.args[0]) == str(task_id): job.remove() status = True task = Task.query.filter_by(id=task_id).first() if task: task.next_run = None db.session.commit() return status
def test_run_task_with_delay(client_fixture: fixture) -> None: p_id, t_id = create_demo_task() delay = 5 page = client_fixture.get(f"/api/run/{t_id}/delay/{delay}") assert page.json == {"message": "Scheduler: task scheduled!"} assert page.status_code == 200 # check that job is in scheduler scheduled_task = [ x for x in atlas_scheduler.get_jobs() if len(x.args) > 0 and x.args[0] == str(t_id) ][0] assert (scheduled_task.next_run_time.replace( microsecond=0, second=0).isoformat() == (datetime.now() + timedelta(minutes=delay)).replace( microsecond=0, second=0, tzinfo=tzlocal()).isoformat())
def job_sync() -> None: """Job to sync run times between model and scheduler.""" try: with atlas_scheduler.app.app_context(): # remove next run date and duration from disabled jobs db.session.execute( update(Task).where(Task.enabled == 0 and (Task.next_run is not None or Task.est_duration is not None)).values( next_run=None, est_duration=None)) db.session.commit() # remove disabled jobs from the scheduler scheduler_jobs = atlas_scheduler.get_jobs() for task in Task.query.filter_by(enabled=0).all(): for job in scheduler_jobs: if job.args and str(job.args[0]) == str(task.id): job.remove() # pylint: disable=broad-except except BaseException as e: print(str(e)) # noqa: T001
def schedule() -> Response: """Build simulated run schedule. Build list of hours to show on the chart: ['now', <now + 1>, <now + 2>, etc] Build list of schedule for next 24 hours Merge two lists and put 0 where needed. """ now = datetime.datetime.now( datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo) tomorrow = now + datetime.timedelta(hours=24) hour_list = ["now"] now_int = now while now_int < tomorrow: now_int = now_int + datetime.timedelta(hours=1) hour_list.append(datetime.datetime.strftime(now_int, "%-H:00")) active_schedule = [] for job in atlas_scheduler.get_jobs(): if (job.id == "job_sync" or not hasattr(job, "next_run_time") or job.next_run_time is None and job.args): continue job_date = job.next_run_time while job_date and job_date < tomorrow: if now.replace(minute=0, second=0, microsecond=0) == job_date.replace(minute=0, second=0, microsecond=0): message = "now" else: message = datetime.datetime.strftime(job_date, "%-H:00") active_schedule.append({"message": message, "date": job_date}) if not job_date.tzinfo: # pragma: no cover job_date.astimezone() job_date = job.trigger.get_next_fire_time(job_date, job_date) active_schedule.sort(key=lambda active_schedule: active_schedule["date"]) groups = { key: list(group) for key, group in groupby( active_schedule, lambda active_schedule: active_schedule["message"]) } active_schedule = [] for hour in hour_list: active_schedule.append({ "case": hour, "count": (sum(1 for x in groups.get(hour)) if groups.get(hour) else 0), # type: ignore[union-attr] }) return jsonify(active_schedule)
def get_scheduled_jobs() -> Response: """Get list of all scheduled job ids.""" return jsonify([ int(job.id.split("-")[1]) for job in atlas_scheduler.get_jobs() if job.next_run_time is not None and re.match(r"^\d+-\d+-.+?$", job.id) ])
def get_jobs() -> Response: """Get list of all job ids.""" return jsonify([ int(job.id.split("-")[1]) for job in atlas_scheduler.get_jobs() if re.match(r"^\d+-\d+-.+?$", job.id) ])