Skip to content

Configuration Improvements #614

@Blacksmoke16

Description

@Blacksmoke16

Current State of Configuration

Since the last major refactor in how Athena applications are configured was completed via #332, the current state of things is pretty good in my opinion. But like anything, it can always be improved.

There are a few "levels" of configuration that an application can make use of:

  1. Constants - Used for in-code configuration of things that rarely change (requires a re-build/deploy to change)
  2. ENV Vars - For configuration that differs machine-to-machine (maybe requires a restart to change)
  3. Static Parameters - Reusable values the change application behavior (%% requires %% a re-build/deploy to change)
  4. Secrets - Sensitive values that are stored in an encrypted state

Currently of these Athena handles 1 and 3 quite well, with 2 being somewhat supported out of the box and 4 essentially not at all. I think I'm okay with not worrying about 4, but would like to focus on improving 2.

ENV Var Configuration

One of the main questions we need to figure out is:

Is there an expectation that changing an ENV var while the server is running would make it so future requests would use that new value?

This has been discussed a bit in the past on Discord, and from that and the thinking i've done since, the answer is likely no. Restarting the server to have it read in updated ENV var values is likely quite sufficient.

Proposed Implementation

The current way ENV vars can be used is defining them directly via the ENV interface. E.g.

ATH.configure({
  parameters: {
    "server_port": ENV["SERVER_PORT"].to_i,
  },
})

The main downside of this is you need to duplicate the logic of converting it from a string into the desired type for each usage. So the idea to handle this would be introduce some abstraction layer to allow doing:

ATH.configure({
  parameters: {
    "server_port": "%env(int:SERVER_PORT)%"
  },
})

The direct ENV module usage can still be used if so desired, but will be discouraged.
Athena itself would provide common processors for bools, ints, floats, and possibly some more complex ones like JSON, URLs, etc depending on use case. Custom processors may also be defined.

While Athena makes heavy use of compile time checks, and Crystal does support reading ENV vars at compile time, the intent is for all env(...) values to be handled at runtime. This ensures the application is more portable since it can pickup the values in the ENV it's currently running, versus where it was built.

The ENV vars will be processed and cached when the server boots up. This means that whatever the state of the ENV vars is when the server starts is what it'll be until it is restarted. This not only keeps things consistent, but also is more performant.

Parameter Container

Another possible iteration on this is to improve on the whole parameters concept to expose them at runtime via a service that could be injected. This would mainly be or cases where a specific service needs a lot of parameters and it isn't ideal to request each one individually.

The service would ideally expose the parameters via type safe getters. But TBD how this could be implemented.

DI Aware Bootstraping

One additional track of work would be abstracting ATH.run behind some additional layer that allows tapping into DI parameters before starting the application. This would be useful for pre-boot operations, both internally and user defined. E.g. processing the ENV vars, or using parameters to define the server port.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions