skip to Main Content

I have a symfony API which runs on AWS beanstalk instances. My .env file registers the environment variables that I need in my app. I override all of them in the AWS console to adapt to my environments.

For exemple :

  • Env file : DEFAULT_CONNECTION_DSN=bolt://user:password@host:port
  • Test server : DEFAULT_CONNECTION_DSN=bolt://test:[email protected]:7687
  • Prod server : DEFAULT_CONNECTION_DSN=bolt://prod:[email protected]:7687

This works because AWS overrides the environment variables when the PHP server is started, so the values placed in the .env file are ignored.

The problem is that I try to create a CRON on the server. The CRON is executed from command line, and I saw that, in this case, the variables still have the value specified in the .env file at runtime.

If I list the environment variables on the server, I see that DEFAULT_CONNECTION_DSN has the value that I want, but if I dump the value in my code (or execute php bin/console debug:container --env-vars), DEFAULT_CONNECTION_DSN has the .env file value. I already tried to delete the entry from my .env file. In this case, I have an error saying my environment variable is not found.

I must precise that I work with a .env.local locally, file which is not versionned, and the deploys are based on git versionning, so it seems difficult to add a .env.env-name file for each environement.

What could I do ?

2

Answers


  1. Symfony loads env vars only if they are not already present. Your problem looks like more how to add env vars with cron in AWS. As I don’t know BS I can’t help you with this.

    In your cron I think you can still run DEFAULT_CONNECTION_DSN=bolt://prod:[email protected]:7687 php bin/console ..., this will set your env var at runtime.

    Login or Signup to reply.
  2. When you run something, from a bash, it inherits the exported variables, plus the ones given in the same command line.

    Suppose this case:

    xavi@bromo:~$ export -p
    declare -x HOME="/home/xavi"
    declare -x TERM="linux"
    declare -x USER="xavi"
    xavi@bromo:~$
    

    Say you echo something not defined: You don’t get anything, as expected:

    xavi@bromo:~$ echo $ABC $XYZ
    
    xavi@bromo:~$
    

    You can place this echo inside a bash script, for example:

    xavi@bromo:~$ cat /tmp/test.sh
    #!/usr/bin/env bash
    echo $ABC $XYZ
    

    Then give it execution permissions:

    xavi@bromo:~$ chmod a+x /tmp/test.sh
    xavi@bromo:~$
    

    Now, if you execute the script it also says nothing, but if you prefix them with variable assignment the value lives “exclussively” inside that call. See examples with hello-bye and orange-banana. If you later just show the values, they are not there:

    xavi@bromo:~$ /tmp/test.sh
    
    xavi@bromo:~$ ABC=hello XYZ=bye /tmp/test.sh
    hello bye
    xavi@bromo:~$ ABC=orange XYZ=banana /tmp/test.sh
    orange banana
    xavi@bromo:~$ echo $ABC $XYZ
    
    xavi@bromo:~$
    

    This would be a good approach for the solution of Fabien Papet: To prefix the cron call with the variable assignment.

    But if you cannot do that, you can go furthter:

    Env vars are not inherited when not exported but inherited when exported: See this:

    xavi@bromo:~$ ABC=pita
    xavi@bromo:~$ XYZ=pota
    xavi@bromo:~$ /tmp/test.sh
    
    xavi@bromo:~$ export ABC=pita
    xavi@bromo:~$ export XYZ=pota
    xavi@bromo:~$ /tmp/test.sh
    pita pota
    

    You could take advantage of bash dot-import command . to import variables.

    Place in these files those contents:

    xavi@bromo:~$ cat /tmp/fruits
    export ABC=orange
    export XYZ=tangerine
    xavi@bromo:~$ cat /tmp/places
    export ABC=Paris
    export XYZ=Barcelona
    xavi@bromo:~$
    

    Note that the previous files do not have a she-bang as they are not meant to be executed, they do not have to create a bash instance. They are meant for inclussion from an existing bash instance.

    Now edit the test.sh to make an inclusion of a file which we’ll pass via the first command line parameter:

    xavi@bromo:~$ cat /tmp/test.sh
    #!/usr/bin/env bash
    
    . $1
    
    echo $ABC $XYZ
    xavi@bromo:~$
    

    You can now play with the invocation. I still have the pita-pota pair from the last test. See what happens:

    xavi@bromo:~$ echo $ABC $XYZ
    pita pota
    xavi@bromo:~$ /tmp/test.sh /tmp/fruits
    orange tangerine
    xavi@bromo:~$ /tmp/test.sh /tmp/places
    Paris Barcelona
    xavi@bromo:~$ echo $ABC $XYZ
    pita pota
    xavi@bromo:~$
    

    The first line echo $ABC $XYZ displays our current environment.

    The second line invokes a new bash (via the she-bang of /tmp/test.sh) and as pita-pota were exported they are momentarily there. But as soon as . $1 is executed, it is expanded into . /tmp/fruits which overrides the environment by exporting new variables, thus the result.

    The second scripts (the one with fruits) ends, so the bash is terminated and its environment is destroyed. We return to our main bash. In here we still have pota-pita. If we had printed now, we’d see the pita-pota. We go with the places, now.

    The reasoning with the places is identical to the reasoning with the fruits.

    As soon as we return to the main bash, the child env is destroyed, so the places have been blown away and we return to the first initial environment with pita-pota, which is then printed.

    So…

    With all this you can:

    1. Setup a bash script that wraps:
      1. loading the environment from some
        place.
      2. Call the php bin/console
    2. In the cron, do not invoke the php but your wrapper script.

    This allows you to

    1. Change the script with different environments without depending on versioning.
    2. Keep your credentials and configuration separated from the code.

    In conclusion:

    • Make your source version control system to have the cron versioned, and the wrapper bash script versioned.
    • Make your deployer to place a different “includable” parameters file in each environment.
    • Make your cron to call the wrapper.
    • Make your wrapper to setup the env vars and call the php bin/console.

    Does this solve your issue?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search