release: v0.12.0 (#520)

Forty-one commits since v0.11.0. See CHANGELOG.md for the full list and the upgrade notes.
This commit is contained in:
Ralksta
2026-08-23 23:18:14 +02:00
committed by GitHub
parent 2f546f440d
commit 10ec68f493
119 changed files with 6888 additions and 758 deletions

View File

@@ -8,7 +8,8 @@
import { NextRequest, NextResponse } from 'next/server';
import { immich } from '@/lib/immich';
import { checkRateLimit, getClientIp, retryAfterSeconds } from '@/lib/rate-limit';
import { getConfig } from '@/lib/config';
import { env } from '@/lib/env';
import { getConfigOrNull } from '@/lib/config';
const startTime = Date.now();
@@ -21,7 +22,11 @@ const CACHE_DURATION_MS = 10_000;
export async function GET(request: NextRequest) {
const ip = getClientIp(request);
const { rateLimitRpm } = getConfig();
// env, not getConfig(): a health check that cannot answer while the content
// config is unparsable is worse than useless — the Dockerfile probes this
// route, so a container with a broken gallery.yaml would restart in a loop at
// exactly the moment the app is still repairable through /admin (#519).
const rateLimitRpm = env.RATE_LIMIT_RPM;
const { success, remaining, resetAt } = checkRateLimit(`health:${ip}`, rateLimitRpm);
if (!success) {
@@ -38,6 +43,28 @@ export async function GET(request: NextRequest) {
);
}
/*
* A config that cannot be parsed is not a reason to kill the container.
* Restarting cannot fix a YAML typo, the app is still serving the setup
* screen, and /admin — where the fix happens — is still reachable. Reporting
* it as unhealthy made the Dockerfile's HEALTHCHECK restart the container in
* a loop at exactly the moment it was still repairable (#519).
*
* Immich itself is not consulted here: the ping reads the same config and
* would answer "unreachable" for a reason that has nothing to do with Immich.
*/
if (!getConfigOrNull()) {
return NextResponse.json(
{
status: 'setup',
config: 'invalid',
immich: 'unknown',
uptime: Math.floor((Date.now() - startTime) / 1000),
},
{ status: 200, headers: { 'Cache-Control': 'no-store' } },
);
}
const now = Date.now();
if (!cachedImmichOkPromise || now - lastCheckTime > CACHE_DURATION_MS) {
cachedImmichOkPromise = immich.ping();
@@ -56,6 +83,7 @@ export async function GET(request: NextRequest) {
const body = {
status: immichOk ? 'ok' : 'degraded',
config: 'ok',
immich: immichOk ? 'connected' : 'unreachable',
uptime: Math.floor((Date.now() - startTime) / 1000),
};