I like combining this with a bash implementation of an event API (https://github.com/bashup/events). This makes it easy/idiomatic, for example, to conditionally add cleanup as you go.
Glossing over some complexity, but roughly:
add_cleanup(){
event on cleanup "$@"
}
trap "event emit 'cleanup'" HUP EXIT
start_postgres(){
add_cleanup stop_postgres
# actually start pg
}
start_apache(){
add_cleanup stop_apache
# actually start apache
}
I wrote a little about some other places where I've used it in https://www.t-ravis.com/post/shell/neighborly_shell_with_bas... and https://t-ravis.com/post/nix/avoid_trap_clobbering_in_nix-sh... (though I make the best use of it in my private bootstrap and backup scripts...)