def test_simple_interval_scheduler(stub_broker, stub_worker, scheduler, scheduler_thread, mul, add):

    result = 0

    @remoulade.actor()
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)
    write_loaded_at.send, event_write = mock_func(write_loaded_at.send)
    mul.send, event_mul = mock_func(mul.send)
    start = time.time()

    # Run scheduler
    scheduler.schedule = [
        ScheduledJob(
            actor_name="write_loaded_at",
            interval=1,
        ),
        ScheduledJob(actor_name="mul", kwargs={"x": 1, "y": 2}, interval=3600),
    ]
    scheduler_thread.start()

    event_write.wait(10)
    event_mul.wait(10)

    stub_broker.join(mul.queue_name)
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()

    end = time.time()
    # should have written ~1 line per second
    assert end - start - 1 <= result <= end - start + 1

    # get the last_queued date for this slow task, this should not change when reloading schedule with new config
    tasks = scheduler.get_redis_schedule().values()
    (slow_task,) = [job for job in tasks if job.actor_name == "mul"]
    last_queued = slow_task.last_queued
    assert {j.actor_name for j in tasks} == {"mul", "write_loaded_at"}

    scheduler.schedule = [
        ScheduledJob(actor_name="add", kwargs={"x": 1, "y": 2}, interval=1),
        ScheduledJob(actor_name="mul", kwargs={"x": 1, "y": 2}, interval=3600),
    ]
    scheduler.sync_config()

    tasks = scheduler.get_redis_schedule().values()
    # One item was deleted
    assert {j.actor_name for j in tasks} == {"add", "mul"}
    # The other one was not updated
    (slow_task,) = [job for job in tasks if job.actor_name == "mul"]
    assert slow_task.last_queued == last_queued
Example #2
0
def test_simple_interval_scheduler(start_scheduler, start_cli):
    from tests.scheduler_configs.simple_1 import broker, write_loaded_at

    client = redis.Redis()

    start = time.time()

    # Run scheduler
    sch = start_scheduler("tests.scheduler_configs.simple_1")

    # And worker
    start_cli(
        "tests.scheduler_configs.simple_1",
        extra_args=["--processes", "1", "--threads", "1", "--watch", "tests"])

    time.sleep(3)

    broker.join(write_loaded_at.queue_name)

    with open("/tmp/scheduler-1", "r") as f:
        text = [x for x in f.read().split("\n") if x]

    end = time.time()

    # should have written ~1 line per second
    assert end - start - 2 <= len(text) <= end - start + 5

    sch.terminate()
    sch.wait()

    # get the last_queued date for this slow task, this should not change when reloading schedule with new config
    tasks = [
        ScheduledJob.decode(v)
        for v in client.hgetall("remoulade-schedule").values()
    ]
    (slow_task, ) = [job for job in tasks if job.actor_name == "mul"]
    last_queued = slow_task.last_queued
    assert {j.actor_name for j in tasks} == {"mul", "write_loaded_at"}

    start_scheduler("tests.scheduler_configs.simple_2")

    time.sleep(1)

    tasks = [
        ScheduledJob.decode(v)
        for v in client.hgetall("remoulade-schedule").values()
    ]
    # One item was deleted
    assert {j.actor_name for j in tasks} == {"add", "mul"}
    # The other one was not updated
    (slow_task, ) = [job for job in tasks if job.actor_name == "mul"]
    assert slow_task.last_queued == last_queued
def test_scheduler_daily_time(stub_broker, stub_worker, scheduler, scheduler_thread, tz):
    result = 0

    @remoulade.actor
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)
    scheduler.get_redis_schedule, event_sch = mock_func(scheduler.get_redis_schedule)
    stub_broker.enqueue, event_enqueue = mock_func(stub_broker.enqueue)

    if tz:
        scheduler.schedule = [
            ScheduledJob(
                actor_name="write_loaded_at",
                daily_time=(
                    datetime.datetime.now(pytz.timezone("Europe/Paris")) + datetime.timedelta(milliseconds=100)
                ).time(),
                tz="Europe/Paris",
            )
        ]
    else:
        scheduler.schedule = [
            ScheduledJob(
                actor_name="write_loaded_at",
                daily_time=(datetime.datetime.utcnow() + datetime.timedelta(milliseconds=100)).time(),
            )
        ]
    scheduler_thread.start()
    # should not have run yet
    assert result == 0

    time.sleep(0.1)

    event_enqueue.wait(10)
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()
    assert result == 1

    event_sch.wait(10)
    event_sch.clear()
    event_sch.wait(10)
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()

    # should not rerun
    assert result == 1
Example #4
0
def test_update_job(scheduler, api_client, do_work):
    scheduler.schedule = [ScheduledJob(actor_name="do_work")]
    scheduler.sync_config()
    res = api_client.put(
        f"/scheduled/jobs/{scheduler.schedule[0].get_hash()}",
        data=json.dumps({"actor_name": "do_work", "enabled": False}),
        content_type="application/json",
    )
    assert res.status_code == 200
    assert res.json == {
        "result": [
            {
                "hash": res.json["result"][0]["hash"],
                "actor_name": "do_work",
                "args": [],
                "daily_time": None,
                "enabled": False,
                "interval": 86400,
                "iso_weekday": None,
                "kwargs": {},
                "last_queued": None,
                "tz": "UTC",
            }
        ]
    }
def test_scheduler_new_daily_time(stub_broker, stub_worker, scheduler, scheduler_thread):
    result = 0

    @remoulade.actor
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)

    scheduler.schedule = [
        ScheduledJob(
            actor_name="write_loaded_at",
            daily_time=(datetime.datetime.utcnow() - datetime.timedelta(seconds=1)).time(),
        )
    ]
    scheduler.get_redis_schedule, event = mock_func(scheduler.get_redis_schedule)
    scheduler_thread.start()
    event.wait(3)
    event.clear()
    event.wait(2)

    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()

    # should not have ran, will run tomorrow
    assert result == 0
def test_scheduler_wrong_weekday(stub_broker, stub_worker, scheduler, scheduler_thread):
    result = 0

    @remoulade.actor
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)

    scheduler.schedule = [
        ScheduledJob(
            actor_name="write_loaded_at",
            iso_weekday=datetime.datetime.now().isoweekday() + 1,
        )
    ]
    scheduler.get_redis_schedule, event = mock_func(scheduler.get_redis_schedule)
    scheduler_thread.start()

    event.wait(2)
    event.clear()
    event.wait(2)

    # do nothing
    assert result == 0
def test_scheduler_right_weekday(stub_broker, stub_worker, scheduler, scheduler_thread):

    result = 0

    @remoulade.actor
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)

    scheduler.schedule = [
        ScheduledJob(
            actor_name="write_loaded_at",
            iso_weekday=datetime.datetime.now().isoweekday(),
        )
    ]
    write_loaded_at.send, event = mock_func(write_loaded_at.send)
    scheduler_thread.start()
    event.wait(2)
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()

    # Should have ran
    assert result == 1
Example #8
0
    def test_scheduled_jobs(self, scheduler, api_client, do_work, frozen_datetime):
        timezone = pytz.timezone("Europe/Paris")
        scheduler.schedule = [
            ScheduledJob(
                actor_name=do_work.actor_name, daily_time=(datetime.datetime.now(timezone)).time(), tz="Europe/Paris"
            )
        ]
        scheduler.sync_config()

        res = api_client.get("/scheduled/jobs")
        jobs = res.json["result"]
        assert jobs == [
            {
                "hash": jobs[0]["hash"],
                "actor_name": "do_work",
                "args": [],
                "daily_time": "01:00:00",
                "enabled": True,
                "interval": 86400,
                "iso_weekday": None,
                "kwargs": {},
                "last_queued": None,
                "tz": "Europe/Paris",
            }
        ]
Example #9
0
def test_api_update_jobs(scheduler, api_client, do_work):
    scheduler.schedule = [ScheduledJob(actor_name="do_work"), ScheduledJob(actor_name="do_other_work")]
    scheduler.sync_config()
    res = api_client.put(
        "/scheduled/jobs",
        data=json.dumps(
            {
                "jobs": {
                    scheduler.schedule[0].get_hash(): {"actor_name": "do_work", "enabled": False},
                    scheduler.schedule[1].get_hash(): {"actor_name": "do_work", "enabled": False, "interval": "55"},
                }
            }
        ),
        content_type="application/json",
    )
    assert res.status_code == 200
    assert len(res.json["result"]) == 2
    for i in range(2):
        assert not res.json["result"][i]["enabled"]
Example #10
0
def test_multiple_schedulers(stub_broker, stub_worker):
    result = 0

    @remoulade.actor
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)
    schedule = [
        ScheduledJob(
            actor_name="write_loaded_at",
            interval=3600,
        )
    ]

    scheduler_list = []
    event_list = []
    thread_list = []

    for _ in range(5):
        sch = new_scheduler(stub_broker)
        sch.get_redis_schedule, event = mock_func(sch.get_redis_schedule)
        event_list.append(event)
        if not scheduler_list:
            check_redis(sch.client)
        sch.schedule = schedule
        scheduler_list.append(sch)
        t = threading.Thread(target=sch.start)
        thread_list.append(t)
        t.start()

    for _ in range(2):
        for event in event_list:
            event.wait(2)
            event.clear()

    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()

    # slow task should run exactly once, even if we launched 2 schedulers
    assert result == 1

    for scheduler in scheduler_list:
        scheduler.stop()

    for thread in thread_list:
        thread.join(10)
Example #11
0
def test_scheduler_daily_time(stub_broker, stub_worker, scheduler, scheduler_thread, tz, frozen_datetime):
    result = 0

    @remoulade.actor
    def write_loaded_at():
        nonlocal result
        result += 1

    stub_broker.declare_actor(write_loaded_at)
    scheduler.get_redis_schedule, event_sch = mock_func(scheduler.get_redis_schedule)
    write_loaded_at.send, event_send = mock_func(write_loaded_at.send)

    scheduler.schedule = [
        ScheduledJob(
            actor_name="write_loaded_at",
            daily_time=(
                datetime.datetime.now(pytz.timezone(tz) if tz else None) + datetime.timedelta(seconds=1)
            ).time(),
            tz=tz,
        )
    ]
    scheduler_thread.start()
    # Wait for sync_config + a complete scheduler iteration
    for _ in range(3):
        event_sch.wait(10)
        event_sch.clear()
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()
    # should not have run yet
    assert result == 0
    frozen_datetime.tick(2)
    # Wait for the ScheduledJob to be sent
    event_send.wait(1)
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()
    assert result == 1

    # Wait for a complete scheduler iteration
    for _ in range(2):
        event_sch.wait(10)
        event_sch.clear()
    stub_broker.join(write_loaded_at.queue_name)
    stub_worker.join()

    # should not rerun
    assert result == 1
Example #12
0
def test_get_scheduled_jobs(scheduler, api_client):
    scheduler.schedule = [ScheduledJob(actor_name="do_work")]
    scheduler.sync_config()
    res = api_client.get("/scheduled/jobs")
    assert res.status_code == 200
    assert res.json == {
        "result": [
            {
                "hash": scheduler.schedule[0].get_hash(),
                "actor_name": "do_work",
                "args": [],
                "daily_time": None,
                "enabled": True,
                "interval": 86400,
                "iso_weekday": None,
                "kwargs": {},
                "last_queued": None,
                "tz": "UTC",
            }
        ]
    }
Example #13
0
import remoulade
from remoulade.brokers.rabbitmq import RabbitmqBroker
from remoulade.scheduler import ScheduledJob, Scheduler

broker = RabbitmqBroker(max_priority=10)
remoulade.set_broker(broker)
remoulade.set_scheduler(
    Scheduler(
        broker,
        [
            ScheduledJob(actor_name="add", kwargs={
                "x": 1,
                "y": 2
            }, interval=1),
            ScheduledJob(
                actor_name="mul", kwargs={
                    "x": 1,
                    "y": 2
                }, interval=3600),
        ],
        period=0.1,
    ))


@remoulade.actor()
def add(x, y):
    return x + y


@remoulade.actor()
def mul(x, y):
Example #14
0
import datetime

import remoulade
from remoulade.scheduler import Scheduler, ScheduledJob
from remoulade.brokers.rabbitmq import RabbitmqBroker

broker = RabbitmqBroker(max_priority=10)
remoulade.set_broker(broker)
remoulade.set_scheduler(
    Scheduler(broker,
              [
                  ScheduledJob(
                      actor_name="write_loaded_at",
                      kwargs={"filename": "/tmp/scheduler-weekday-1", "text": "simple schedule\n"},
                      iso_weekday=datetime.datetime.now().isoweekday() + 1
                  )
              ], period=0.1)
)


@remoulade.actor()
def write_loaded_at(filename, text):
    with open(filename, "a+") as f:
        f.write(text)


broker.declare_actor(write_loaded_at)
Example #15
0
def add_job(scheduler, **kwargs):
    scheduler.add_job(ScheduledJob(**kwargs))
Example #16
0
def test_add_job(scheduler):
    job = ScheduledJob(actor_name="do_work")
    scheduler.add_job(job)
    hashes = list(scheduler.get_redis_schedule().keys())
    assert len(hashes) == 1
    assert hashes[0] == job.get_hash()
Example #17
0
def test_delete_job(scheduler):
    scheduler.schedule = [ScheduledJob(actor_name="do_work")]
    scheduler.sync_config()
    scheduler.delete_job(scheduler.schedule[0].get_hash())
    assert scheduler.get_redis_schedule() == {}
Example #18
0
import pytz

import remoulade
from remoulade.scheduler import Scheduler, ScheduledJob
from remoulade.brokers.rabbitmq import RabbitmqBroker

broker = RabbitmqBroker(max_priority=10)
remoulade.set_broker(broker)
timezone = pytz.timezone("Europe/Paris")
remoulade.set_scheduler(
    Scheduler(broker, [
        ScheduledJob(actor_name="write_loaded_at",
                     kwargs={
                         "filename": "/tmp/scheduler-daily_tz",
                         "text": "simple schedule\n"
                     },
                     daily_time=(datetime.datetime.now(timezone) +
                                 datetime.timedelta(seconds=5)).time(),
                     tz="Europe/Paris")
    ],
              period=0.1))


@remoulade.actor()
def write_loaded_at(filename, text):
    with open(filename, "a+") as f:
        f.write(text)


broker.declare_actor(write_loaded_at)
Example #19
0
def update_jobs(scheduler, **kwargs):
    for job_hash, job_dict in kwargs["jobs"].items():
        scheduler.delete_job(job_hash)
        scheduler.add_job(ScheduledJob(**job_dict))
Example #20
0
def test_api_delete_job(scheduler, api_client):
    scheduler.schedule = [ScheduledJob(actor_name="do_work")]
    scheduler.sync_config()
    res = api_client.delete(f"/scheduled/jobs/{scheduler.schedule[0].get_hash()}")
    assert res.status_code == 200
    assert res.json == {"result": []}
Example #21
0
from remoulade.brokers.rabbitmq import RabbitmqBroker
from remoulade.scheduler import ScheduledJob, Scheduler

broker = RabbitmqBroker()
remoulade.set_broker(broker)


@remoulade.actor()
def count_words(url):
    response = requests.get(url).text
    print("There are {} words in {}".format(len(response), url))


broker.declare_actor(count_words)

if __name__ == "__main__":
    scheduler = Scheduler(
        broker,
        [
            ScheduledJob(actor_name="count_words",
                         kwargs={"url": "https://github.com"},
                         interval=1),
            ScheduledJob(actor_name="count_words",
                         kwargs={"url": "https://gitlab.com"},
                         interval=10),
        ],
        period=0.1,  # scheduler run each 0.1 (second)
    )
    remoulade.set_scheduler(scheduler)
    scheduler.start()
Example #22
0
import remoulade
from remoulade.scheduler import Scheduler, ScheduledJob
from remoulade.brokers.rabbitmq import RabbitmqBroker

broker = RabbitmqBroker(max_priority=10)
remoulade.set_broker(broker)
remoulade.set_scheduler(
    Scheduler(broker, [
        ScheduledJob(actor_name="write_loaded_at",
                     kwargs={
                         "filename": "/tmp/scheduler-1",
                         "text": "simple schëdule\n"
                     },
                     interval=1),
        ScheduledJob(actor_name="mul", kwargs={
            "x": 1,
            "y": 2
        }, interval=3600)
    ],
              period=0.1))


@remoulade.actor()
def write_loaded_at(filename, text):
    with open(filename, "a+") as f:
        f.write(text)


@remoulade.actor()
def mul(x, y):
    return x * y
Example #23
0
import datetime

import remoulade
from remoulade.scheduler import Scheduler, ScheduledJob
from remoulade.brokers.rabbitmq import RabbitmqBroker

broker = RabbitmqBroker(max_priority=10)
remoulade.set_broker(broker)
remoulade.set_scheduler(
    Scheduler(broker,
              [
                  ScheduledJob(
                      actor_name="write_loaded_at", kwargs={"filename": "/tmp/scheduler-daily-new",
                                                            "text": "simple schedule\n"},
                      daily_time=(datetime.datetime.utcnow() - datetime.timedelta(seconds=60)).time()
                  )
              ], period=0.1)
)


@remoulade.actor()
def write_loaded_at(filename, text):
    with open(filename, "a+") as f:
        f.write(text)


broker.declare_actor(write_loaded_at)
Example #24
0
import remoulade
from remoulade.scheduler import Scheduler, ScheduledJob
from remoulade.brokers.rabbitmq import RabbitmqBroker

broker = RabbitmqBroker(max_priority=10)
remoulade.set_broker(broker)
remoulade.set_scheduler(
    Scheduler(broker, [
        ScheduledJob(actor_name="write_loaded_at",
                     kwargs={
                         "filename": "/tmp/scheduler-2",
                         "text": "simple schedule\n"
                     },
                     interval=3600)
    ],
              period=0.1))


@remoulade.actor()
def write_loaded_at(filename, text):
    with open(filename, "a+") as f:
        f.write(text)


broker.declare_actor(write_loaded_at)
Example #25
0
def update_job(scheduler, job_hash, **kwargs):
    scheduler.delete_job(job_hash)
    scheduler.add_job(ScheduledJob(**kwargs))