Devenv.sh: Starting Postgres

I have the following in devenv.nix:

{ pkgs, ... }:
{
	env.LOCALE_ARCHIVE_2_27 = "${pkgs.glibcLocales}/lib/locale/locale-archive";
	env.PGDATA              = "/tmp/postgres/12";
	env.TZ                  = "UTC";
	env.PGUSER              = "postgres";

    packages = [ pkgs.postgresql_12 ];

    enterShell = ''
		echo $PGUSER >/tmp/password.txt
		initdb --username=$PGUSER --encoding=UTF-8 --locale=en_US.UTF-8 --auth=md5 --pwfile=/tmp/password.txt
		rm /tmp/password.txt
		mkdir -p "$PGDATA/run" "$PGDATA/logs"
		sed -i -e "s@#unix_socket_directories  *=  *.*@unix_socket_directories = '$PGDATA/run'@" $PGDATA/postgresql.conf
		pg_ctl --log $PGDATA/logs/postgres.log start
		echo "Postgres started"
    '';
}

This works (i.e. the database is started successfully) but I never(?) get the prompt back (after entering the directory with devenv.nix, using direnv).

If I add pg_ctl stop after the last line (echo ...), everything works as expected and I do get the prompt back.

It appears that “something” (direnv maybe?) notices the new process and continues to wait for it?

Thoughts?

You can tell devenv to start a postgres for you:

That clashes with my PGDATA. I appreciate that there is a default way to start Postgres but I want/need more control.

Given that services.postgres.enable exists, what is done differently there? I tried using exec (that I found there) but I still get the same problem: no prompt.

Hmm. I’d try adding a set -x to your enterShell script. If everything is running in the same shell process it might help clarify what’s going on?

Modern pg_ctl start should wait until the server starts before returning, so I guess it could be failing to do so, but that doesn’t square w/ your note about adding a pg_ctl stop fixing the behavior.

Are you certain it’s stable behavior? Do you see pg processes from outside of the environment? I don’t see an attempt to stop/kill the server on exit, so you might be seeing ~stateful behavior from already-running processes leftover from previous attempts?

The script finishes. The echo is executed after all. And yes, I can see in a separate terminal that everything is running as expected. It seems to be just about what happens after enterShell finishes.

It is totally repeatable (at least by me). I wanted to keep the script as simple as possible but I stop PG and remove the PGDATA directory manually.

I’ll try adding set -x.

With set -x I get the following (additional) output:

++++ echo 'Postgres started'                                                                                                                                                                                                                                                   
Postgres started                                                                                                                                                                                                                                                               
++++ export 'PS1=\e[0;34m(devenv)\e[0m '                                                                                                                                                                                                                                       
++++ PS1='\e[0;34m(devenv)\e[0m '                                                                                                                                                                                                                                              
++++ [[ ! '' =~ (^|:)~/my-directory(:|$) ]]                                                                                                                                                                                                                  
++++ export DIRENV_ACTIVE=~/my-directory:                                                                                                                                                                                                                    
++++ DIRENV_ACTIVE=~/my-directory:                                                                                                                                                                                                                           
++++ '[' '!' type -p direnv
++++ rm -f .devenv/profile
++++ ln -s /nix/store/lfzvzczn0036hciqc3cvvyi6k2x07v5i-devenv-profile .devenv/profile
+ popd
+ popd
+ __dump_at_exit
+ local ret=0
+ /nix/store/pzb1yf5kmp6rhy4b33lfxb4ccrg959gc-direnv-2.32.2/bin/direnv dump json ''
+ trap - EXIT
+ exit 0

(The echo 'Postgres started' is the last line of my enterShell.)

If I add pg_ctl stop after that final echo, the output is identical except for the additional line output by direnv about the exported variables. And I get my prompt back.

Do you regain control inside the environment you expect, or outside of it? (Wondering, since we’re seeing an exit here).

I do see Direnv hangs when a subprocess doesn't exit(?) · Issue #755 · direnv/direnv · GitHub. IDK if that would be getting tripped by the running PG processes? Does it go ahead and continue if you try to enter, wait for it to hang, and then kill the pg processes from outside of the shell?

The “original” terminal simply hangs. I can’t ctrl-c it but I can close the terminal tab and it will die (it no longer shows up in ps -ef). Other terminals show that all expected effects/actions have taken place.

The issue you linked to seems to be exactly what I am running into. And indeed, your suggestion about killing PG in another terminal does result in the “original” terminal to finish and I get back my prompt.

1 Like

And indeed, using that background function, it all works … except I no longer get any output (for that part and what comes next).

1 Like

Ah, but I can use my earlier trick. I first start PG, create the database, and then stop PG. After that, I use the background trick. It’s redundant but the database creation only happens once (or rarely).

2 Likes