Exemplo n.º 1
0
    def test_async_task(self):
        with schema_context('testone'):
            task_id = QUtilities.add_async_task(
                'core.tasks.print_users_in_tenant')
            print(QUtilities.fetch_task(task_id))

        with schema_context('testtwo'):
            task_id = QUtilities.add_async_task(
                'core.tasks.print_users_in_tenant')
            print(QUtilities.fetch_task(task_id))
 def run(self):
     self.id = QUtilities.add_async_task(self.func, *self.args,
                                         **self.kwargs)
     self.started = True
     return self.id
def scheduler(broker=None):
    """
    Creates a task from a schedule at the scheduled time and schedules next run
    """
    if not broker:
        broker = get_broker()
    close_old_django_connections()
    tenant_model = get_tenant_model()
    tenant_schemas_to_exclude = getattr(
        settings, 'SCHEMAS_TO_BE_EXCLUDED_BY_SCHEDULER', ['public'])

    try:
        for tenant in tenant_model.objects.exclude(schema_name__in=tenant_schemas_to_exclude):
            with schema_context(tenant.schema_name):
                with db.transaction.atomic():
                    for s in (
                        Schedule.objects.select_for_update()
                        .exclude(repeats=0)
                        .filter(next_run__lt=timezone.now())
                    ):
                        args = ()
                        kwargs = {}
                        # get args, kwargs and hook
                        if s.kwargs:
                            try:
                                # eval should be safe here because dict()
                                kwargs = eval(f"dict({s.kwargs})")
                            except SyntaxError:
                                kwargs = {}
                        if s.args:
                            args = ast.literal_eval(s.args)
                            # single value won't eval to tuple, so:
                            if type(args) != tuple:
                                args = (args,)
                        q_options = kwargs.get("q_options", {})
                        if s.hook:
                            q_options["hook"] = s.hook
                        # set up the next run time
                        if not s.schedule_type == s.ONCE:
                            next_run = arrow.get(s.next_run)
                            while True:
                                if s.schedule_type == s.MINUTES:
                                    next_run = next_run.shift(
                                        minutes=+(s.minutes or 1))
                                elif s.schedule_type == s.HOURLY:
                                    next_run = next_run.shift(hours=+1)
                                elif s.schedule_type == s.DAILY:
                                    next_run = next_run.shift(days=+1)
                                elif s.schedule_type == s.WEEKLY:
                                    next_run = next_run.shift(weeks=+1)
                                elif s.schedule_type == s.MONTHLY:
                                    next_run = next_run.shift(months=+1)
                                elif s.schedule_type == s.QUARTERLY:
                                    next_run = next_run.shift(months=+3)
                                elif s.schedule_type == s.YEARLY:
                                    next_run = next_run.shift(years=+1)
                                elif s.schedule_type == s.CRON:
                                    next_run = croniter(s.cron, timezone.datetime.now()).get_next(timezone.datetime)
                                if Conf.CATCH_UP or next_run > arrow.utcnow():
                                    break
                            if s.schedule_type == s.CRON:
                                s.next_run = next_run
                            else:
                                s.next_run = next_run.datetime
                            s.repeats += -1
                        # send it to the cluster
                        q_options["broker"] = broker
                        q_options["group"] = q_options.get(
                            "group", s.name or s.id)
                        kwargs["q_options"] = q_options
                        s.task = QUtilities.add_async_task(
                            s.func, *args, **kwargs)
                        # log it
                        if not s.task:
                            logger.error(
                                _(
                                    f"{current_process().name} failed to create a task from schedule [{s.name or s.id}] under tenant {kwargs.get('schema_name', 'UNSPECIFIED')}"
                                )
                            )
                        else:
                            logger.info(
                                _(
                                    f"{current_process().name} created a task from schedule [{s.name or s.id}] under tenant {kwargs.get('schema_name', 'UNSPECIFIED')}"
                                )
                            )
                        # default behavior is to delete a ONCE schedule
                        if s.schedule_type == s.ONCE:
                            if s.repeats < 0:
                                s.delete()
                                continue
                            # but not if it has a positive repeats
                            s.repeats = 0
                        # save the schedule
                        s.save()
    except Exception as e:
        logger.error(e)