Skip to content

Commit 9e7d822

Browse files
committed
add api backend healthcheck and make python wait for it
1 parent 0db23f7 commit 9e7d822

File tree

7 files changed

+110
-2
lines changed

7 files changed

+110
-2
lines changed

config/packages/api_platform.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ api_platform:
1313
- "%kernel.project_dir%/src/FieldHolder/Place/Domain/Exception/"
1414
- "%kernel.project_dir%/src/FieldHolder/Community/Domain/Exception/"
1515
- "%kernel.project_dir%/src/Field/Domain/Exception/"
16+
- "%kernel.project_dir%/src/System/Infrastructure/ApiPlatform/Resource/"
1617
formats:
1718
json: ["application/json"]
1819
jsonld: ["application/ld+json"]

config/packages/security.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ security:
2929
# Easy way to control access for large sections of your site
3030
# Note: Only the *first* access control that matches will be used
3131
access_control:
32-
- { host: '%host_api%', path: ^/system/healthcheck, roles: PUBLIC_ACCESS, ips: ['127.0.0.1'] }
3332
# - { path: ^/admin, roles: ROLE_ADMIN }
3433
# - { path: ^/, roles: ROLE_USER }
3534

docker/python/Dockerfile

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ RUN pip install -Ur requirements.txt
1212

1313
FROM python:3.9-slim as runner
1414
WORKDIR /app/
15+
16+
RUN apt update && apt install -y \
17+
curl \
18+
jq \
19+
&& apt clean
20+
1521
COPY --from=compiler /opt/venv /opt/venv
1622

1723
COPY usr/local/bin/docker-python-entrypoint /usr/local/bin/docker-python-entrypoint

src/FieldHolder/Community/Infrastructure/ApiPlatform/Resource/CommunityResource.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@
4848
normalizationContext: ['groups' => ['communities']],
4949
),
5050
new Put(
51-
security: 'is_granted("ROLE_AGENT")',
5251
uriTemplate: '/communities/upsert',
5352
status: 200,
5453
processor: UpsertCommunityProcessor::class,
5554
input: CommunityWikidataInput::class,
5655
),
5756
new GetCollection(
57+
security: 'is_granted("ROLE_AGENT")',
5858
filters: [
5959
FieldTypeFilter::class,
6060
FieldWikidataIdFilter::class,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\System\Infrastructure\ApiPlatform\Resource;
6+
7+
use ApiPlatform\Metadata\ApiResource;
8+
use ApiPlatform\Metadata\Get;
9+
use App\System\Infrastructure\ApiPlatform\State\Provider\SystemHealthCheckProvider;
10+
11+
#[ApiResource(
12+
shortName: 'System',
13+
operations: [
14+
new Get(
15+
uriTemplate: '/system/health-check',
16+
provider: SystemHealthCheckProvider::class,
17+
),
18+
],
19+
)]
20+
final class SystemHealthCheckResource
21+
{
22+
public function __construct(
23+
public bool $mysql = false,
24+
25+
public bool $redis = false,
26+
) {
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\System\Infrastructure\ApiPlatform\State\Provider;
6+
7+
use ApiPlatform\Metadata\Operation;
8+
use ApiPlatform\State\ProviderInterface;
9+
use App\Core\Infrastructure\Redis\RedisClient;
10+
use App\System\Infrastructure\ApiPlatform\Resource\SystemHealthCheckResource;
11+
use Doctrine\DBAL\Exception\ConnectionException;
12+
use Doctrine\ORM\EntityManagerInterface;
13+
14+
/**
15+
* @implements ProviderInterface<SystemHealthCheckResource>
16+
*/
17+
final class SystemHealthCheckProvider implements ProviderInterface
18+
{
19+
public function __construct(
20+
private readonly RedisClient $redisClient,
21+
private readonly EntityManagerInterface $em,
22+
) {
23+
}
24+
25+
public function provide(Operation $operation, array $uriVariables = [], array $context = []): SystemHealthCheckResource
26+
{
27+
$isMySQLUp = false;
28+
try {
29+
$this->em->getConnection()->fetchOne('SELECT 1');
30+
$isMySQLUp = true;
31+
} catch (ConnectionException) {
32+
}
33+
34+
$isRedisUp = (bool) $this->redisClient->client->ping();
35+
36+
return new SystemHealthCheckResource(
37+
mysql: $isMySQLUp,
38+
redis: $isRedisUp,
39+
);
40+
}
41+
}

usr/local/bin/docker-python-entrypoint

+33
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,39 @@ set -e
44
env > /etc/environment
55
echo -------------------; echo Versions: ; python --version ; pip --version ; echo -------------------
66

7+
MAX_RETRIES=150
8+
RETRY_INTERVAL=10
9+
10+
check_health() {
11+
response=$(curl -k $OPENCHURCH_HOST/system/health-check)
12+
if ! echo "$response" | jq -e . >/dev/null 2>&1; then
13+
return 1
14+
fi
15+
16+
mysql_status=$(echo "$response" | jq -r '.mysql')
17+
redis_status=$(echo "$response" | jq -r '.redis')
18+
19+
if [ "$mysql_status" = "true" ] && [ "$redis_status" = "true" ]; then
20+
return 0
21+
else
22+
return 1
23+
fi
24+
}
25+
26+
counter=0
27+
until check_health; do
28+
counter=$((counter + 1))
29+
if [ $counter -eq $MAX_RETRIES ]; then
30+
echo "api backend service unavailble after $MAX_RETRIES attemps"
31+
exit 1
32+
fi
33+
34+
echo "Attempt $counter/$MAX_RETRIES - api backend unavailable. New attempt in $RETRY_INTERVAL seconds..."
35+
sleep $RETRY_INTERVAL
36+
done
37+
38+
echo "api backend service is now available"
39+
740
while true; do
841
/opt/venv/bin/python /app/synchro.py --entity-only diocese
942
/opt/venv/bin/python /app/synchro.py --entity-only parish

0 commit comments

Comments
 (0)