Search code examples
djangoazurecronazure-web-app-servicevirtualenv

Load variables from a virtual env for a cron task on Azure web app server


I have a python (Django) web app running on Azure App Service.

Despite everything I tried from other SO threads, I can't figure out how to have the environment variables accessed from my cron tasks. It may be caused by how Azure duplicates the venv into a weird antenv. More on that later.

What I really want is to use Django commands in cron, like ./manage.py some_command. However, I quickly realized that the Django virtual env is not loaded properly in cron. So I decided to go step by step and see how to access the virtual env from cron.

What I have tried

Initial implementation

I am testing my setup using Azure App Service SSH console available at https://{my-app-name}.scm.azurewebsites.net/webssh/host.

Script

I created a script /home/scripts/log-env.sh to test the water:

#!/bin/bash
trace=/home/scripts/trace
path=$(...) # Some command that locates the venv directory
echo "src path: ${path}" > ${trace}  # I can see ${path} is set correctly
echo "MY_VAR before source: [${MY_VAR}]" >> ${trace}
source ${path}/antenv/bin/activate; echo "MY_VAR same command line as source: [${MY_VAR}]" >> ${trace}
echo "MY_VAR after source: [${MY_VAR}]" >> ${trace}

Output

When I run the script in the terminal, it shows that I don't even need to source the venv, as $MY_VAR is accessible before source is called:

# Content of trace file /home/scripts/trace when script runs in the terminal
src path: /tmp/8dbe5c185e85419
$MY_VAR before source: [expected_value]
$MY_VAR same command line as source: [expected_value]
$MY_VAR after source: [expected_value]

But when it runs from cron, $MY_VAR is not accessed, neither before nor after the venv is activated:

# Content of trace file /home/scripts/trace when script runs in cron
src path: /tmp/8dbe5c185e85419
$MY_VAR before source: []  # empty
$MY_VAR same command line as source: []  # empty
$MY_VAR after source: []  # empty

cron

I added the following entry to crontab:

> crontab -l
* * * * * bash /home/scripts/log-env.sh > /home/scripts/cron.log 2>&1

Other attempts

I tried the following changes that solved other questions on SO but didn't work in my case:

Add SHELL=/bin/bash on top of the crontab:

> crontab -l
SHELL=/bin/bash
* * * * * bash /home/scripts/log-env.sh > /home/scripts/cron.log 2>&1

Source in cron

> crontab -l
* * * * * cd /tmp/8dbe5c185e85419 && source /tmp/8dbe5c185e85419/antenv/bin/activate && /home/scripts/log-env.sh > /home/scripts/cron.log 2>&1

Azure antenv/ vs usual venv/

For some reason, Azure server has a antenv/ directory:

(antenv) root@23e4a05be277:/tmp/8dbe5c185e85419# ls -l *env
antenv:
total 16
drwxr-xr-x 2 root root 4096 Nov 15 16:30 bin
drwxr-xr-x 3 root root 4096 Nov 15 16:30 include
drwxr-xr-x 3 root root 4096 Nov 15 16:30 lib
-rw-r--r-- 1 root root  287 Nov 15 16:30 pyvenv.cfg

venv:
total 20
drwxr-xr-x 2 root root 4096 Nov 15 16:30 bin
drwxr-xr-x 3 root root 4096 Nov 15 16:30 include
drwxr-xr-x 3 root root 4096 Nov 15 16:30 lib
drwxr-xr-x 3 root root 4096 Nov 15 16:30 lib64
-rwxr-xr-x 1 root root  282 Nov 15 16:30 pyvenv.cfg

It's the environment set by default. It is active when connecting to SSH, as the (antenv) prefix shows in the prompt:

(antenv) root@23e4a05be277:/tmp/8dbe5c185e85419

The pyvenv.cfg files look like as follows:

root@23e4a05be277:/tmp/8dbe5c185e85419# cat *env/*.cfg
# antenv/pyvenv.cfg
home = /tmp/oryx/platforms/python/3.11.6/bin
include-system-site-packages = true
version = 3.11.6
executable = /tmp/oryx/platforms/python/3.11.6/bin/python3.11
command = /tmp/oryx/platforms/python/3.11.6/bin/python3.11 -m venv --copies --system-site-packages /tmp/8dbe5c185e85419/antenv

# venv/pyvenv.cfg
home = /opt/hostedtoolcache/Python/3.11.6/x64/bin
include-system-site-packages = false
version = 3.11.6
executable = /opt/hostedtoolcache/Python/3.11.6/x64/bin/python3.11
command = /opt/hostedtoolcache/Python/3.11.6/x64/bin/python -m venv /home/runner/work/jobalerts/jobalerts/venv

I tried the various changes with antenv as well as with venv. None worked.

Needless to say I am way out of my depth here. Any help with this mess is welcome.


Solution

  • As I wrote in a comment, for now, the least horrible workaround I found is this one: https://learn.microsoft.com/en-us/answers/questions/719903/how-to-set-my-django-apps-management-commands-as-c

    I am not a huge fan of using sleep though. Since scheduling is a key part of my product, I'll look at alternatives to Azure and see if I could use cron there.