Skip to main content

Hosting

The hosting bundle is a small bundle, that includes several fundamental tasks, that every project needs.

Installation

Start with installing the package:

composer require 21torr/hosting

If you are using Symfony Flex you are all set.

Manual configuration

Create the env var:

.env
HOSTING_TIER=development
HOSTING_INSTALLATION="add your custom key here"

Then create the config:

config/packages/hosting.yaml
hosting:
tier: '%env(HOSTING_TIER)%'
installation: ''%env(HOSTING_INSTALLATION)%'

Setup

The bundle contains two CLI tasks, that you should integrate into your workflow:

# This command should be run once after your build finished:
bin/console hosting:run-tasks:post-build

# This command should be run once after your deployment finished:
bin/console hosting:run-tasks:post-deploy

Features

Hosting Tier

You can define three hosting tiers:

  • development (probably your local machine)
  • staging
  • production

Using the HostingTier service, you can define tasks that should only run on certain environments:

function syncToExternalSystem ()
{
if (!$this->hostingTier->isProduction())
{
throw new Error("Syncing to external system is only allowed in production");
}

// ...
}

Installation Key

The installation key can be embedded as HTML comment in your output, to be able to match this unique key when doing uptime checks. This ensures, that the correct page / system is reachable on a given URL.

Build Info

You can also embed important build parameters into a static build info, that the running app can then show as info to an admin.

You can add custom build info by hooking into the CollectBuildInfoEvent event.

class CollectBuildInfoEventListener
{
#[AsEventListener(CollectBuildInfoEvent::class)]
public function onCollectBuildInfo (CollectBuildInfoEvent $event) : void
{
$event->set("app.test", "123");
}
}

The info is written as JSON file to .build-info.json in your project directory and is supposed to be deployed to the production environment.

You can then fetch the build info during runtime using BuildInfoStorage::getBuildInfo().

There are automatic build info integrations for the following info:

  • built a timestamp of when the app was built
  • git.last-tag the latest git tag in the current branch1
  • git.commit the HEAD commit hash1

Hooks

This bundle provides infrastructure for your app to run one-time hooks after build or deployment.

These are called using the console commands:

bin/console hosting:hook:build
bin/console hosting:hook:deploy

You can integrate into them by implementing the BuildHookInterface or DeployHookInterface interfaces respectively. Use autoconfiguration, then everything works out-of-the-box.

Every task has basically a label and a callback that can perform certain tasks:

use Torr\Hosting\Deployment\BuildHookInterface;

class MyBuildTask implements BuildHookInterface
{
/**
*/
public function getLabel () : string
{
return "My Task";
}

/**
*/
public function runPostBuild (TaskCli $io) : void
{
// perform your tasks here
}
}

App Validation

App validation is a CLI command, that is intended to be used in your CLI, where your app can verify that the app is internally configured correctly.

This can include more sophisticated checks, like checking that certain API tokens in your secrets are valid.

You can integrate into the validation process with events:

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Torr\Hosting\Event\ValidateAppEvent;
use Torr\Hosting\Hosting\HostingEnvironment;
use Torr\Hosting\Tier\HostingTier;

readonly class ValidateAppListener
{

#[AsEventListener]
public function onValidateApp (ValidateAppEvent $event) : void
{
$event->markAppAsInvalid("Something is invalid");
}
}

You can do your custom checks and mark the app as invalid. Please note that your message when marking as invalid is included in the API response, so it is public.

When no check marks the app as invalid, it is assumed to be valid.

warning

Please note that, as this check is running the CI, the database is normally not available for doing any checks.

Health Checks

The hosting bundle includes system to implement live and ready health checks:

  • live: The app is working correctly.
  • ready: The app is ready to accept connections

These checks can be used by an Hypervisor when provisioning containers with the app. Please be aware, that failing a live health check will lead to the container being destroyed / restarted.

caution

Only issues that can be solved by a potential restart should fail the health check.

e.g. failing the live health check due to a permanent config error will lead to your container continuously being restarted.

You can integrate into the health checks with the corresponding events:

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Torr\Hosting\Event\HealthCheckLiveEvent;
use Torr\Hosting\Event\HealthCheckReadyEvent;

class MyHealthCheckListener
{
#[AsEventListener]
public function onLiveCheck (HealthCheckLiveEvent $event) : void
{
// ...
}

#[AsEventListener]
public function onLiveCheck (HealthCheckReadyEvent $event) : void
{
// ...
$event->markAsFailed("my check failed");
}
}

You can mark the check as failed. Please note that your message when failing the health check is included in the API response, so it is public.

When no check marks anything as failed, it is assumed to be healthy.

API Endpoints

After proper configuration, the bundle automatically provides two endpoints for the health checks:

  • /hosting/health/live: Liveness health check
  • /hosting/health/ready: Readiness health check

Footnotes

  1. Only available if the git executable and a repository is found. 2