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)