Miserlou / Zappa

Serverless Python
https://blog.zappa.io/
MIT License
11.89k stars 1.2k forks source link

Schedule django management command #1123

Open aarcro opened 7 years ago

aarcro commented 7 years ago

It's so easy to run zappa manage migrate

It would be awesome to do

events:
  - manage: migrate
    expression: rate(1 minute)

Note: not actually for the migrate command, but things like django-post_office's send_queued_mail

ebertti commented 6 years ago

To fix it, I need to create a function to run every command, like this:

# crons.py

def migrate():
    from django.core.management import call_command
    call_command('migrate')
# zappa_settings.yaml

events:
  - function: "crons.migrate"
    expression: rate(1 minute)
aarcro commented 6 years ago

But this won't run through the Django start up mechanism will it?

ebertti commented 6 years ago

Will! This works fine.

I has the same question on my mind, but I try it and works fine.

In my action, I have models and cache used 💃

mwalker commented 6 years ago

Thanks @ebertti this was really useful.

symroe commented 6 years ago

To save writing a function for each commend, I've come up with this hack that some might find helpful.

In a file called zappa_commands.py, I have:

class Runner:
    def __getattr__(self, attr):
        from django.core.management import call_command
        return lambda: call_command(attr)

import sys
sys.modules[__name__] = Runner()

I can then do the following in zappa_settings.json:

{
  "function": "zappa_commands.some_command",
  "expression": "rate(2 hours)"
}

This does a few things:

  1. Turn the whole module in to a class. This is what sys.modules[__name__] = Runner() is doing.

  2. Overwrite __getattr__ on the class. Remember this is now __getattr__ on the file/module because the file is the class.

  3. For any attr, return a python lambda that when called will return a function that can be called by AWS Lambda.

I'm not especially proud of this, but it's working and I think it reasonable in the context of gluing commands to something I can call on a schedule. I still can't pass any arguments to the command, but that's ok in my case.

elcolie commented 4 years ago

Please add official document on Django schedule command. It is very useful knowledge

anentropic commented 12 months ago

thanks to @symroe for the handy workaround!

as a tidier alternative to instantiating a class and fiddling with sys.modules... in Python 3.7+ we can use a module-level __getattr__

so create a module e.g. django_commands.py like:

def __getattr__(self, attr):
    from django.core.management import call_command, get_commands
    if attr in get_commands():
        return lambda: call_command(attr)
    else:
        raise AttributeError(f"Django command {attr!r} not found")

(...I suspect the django import could be at the top level but haven't tested moving it yet)

and then in zappa settings:

{
  "function": "django_commands.some_command",
  "expression": "rate(2 hours)"
}
ivan-halo commented 3 months ago

Hi! Its been working for a while, but today it lost all commands... for some reason it doesn't see any other then core one... Does anyone faced this issue?