Continuing with the example of an application that can either use a Redis or PostgreSQL backend, you could have a plan.sh
that includes something like this:
pkg_binds_optional=(
[redis]="...",
[database]="..."
)
(The "..."
serve as placeholders for whatever exported data you would need for those binds… they could be as simple as "port"
, but it depends on the specific things you’re wanting to bind to.)
If you want to start your application with the Redis backend, you would just bind that to a service group, like so:
hab svc load my/awesome-app --bind=redis:redis.default
(assuming you have a redis.default
service group in your environment)
This will ensure that my/awesome-app
will not start until members of the redis.default
group are present; once they are, their exported data are available to use in the templates of the application, which would be written such that they would “do the right thing”, depending on which bind was present. That might look something like this:
{{ #if bind.redis }}
... do redis stuff
{{ /if }}
{{ #if bind.database }}
... do database stuff instead
{{ /if }}
In another deployment scenario, you could deploy your service using the database backend instead. That would look like this:
hab svc load my/awesome-app --bind=database:postgresql.default
Similarly, this will block startup of my/awesome-app
until members of the postgresql.default
group are present.
It should be noted that the use of “optional” here means that you can choose to bind to something or not, but your application will henceforth require them to be present in order to start. I’m currently working on a refinement to our binding logic that will make it so binds can be present or not, and your application will still be able to run… this is how properly designed distributed services should behave anyway. This will allow your application to degrade gracefully if one of its dependencies goes away.