Reconnect options (-reconnect, -reconnect_streamed, etc.) only apply to
network inputs and cause 'Option reconnect not found' errors when the
input is pipe:0. Curl already handles connection resilience.
The previous -max_alloc approach does not fix the 'overlong headers' error
because FFmpeg 5.1 (Debian bookworm) uses a compile-time stack-allocated
buffer (MAX_URL_SIZE=4096) for HTTP response headers, which -max_alloc
cannot change.
Instead, when the stream URL is HTTP/HTTPS, launch curl to handle the
HTTP connection and pipe its stdout to FFmpeg via stdin (pipe:0). Curl
does not have the 4096-byte header limit, so it handles oversized CDN
response headers from Douyin without error.
Additional changes:
- RequestStopAsync kills curl first (instead of sending 'q' to FFmpeg),
causing the pipe to close and FFmpeg to exit gracefully on EOF.
- SessionProcessRuntime tracks the curl process for cleanup.
- Add -max_alloc 100000000 to FFmpeg arguments for HTTP inputs to avoid
'overlong headers' error when CDN (e.g. Douyin) returns oversized HTTP
response headers exceeding FFmpeg's default 4096-byte buffer.
- Add exponential backoff for repeated startup failures (30s → 15min cap)
to break the tight fail→retry→re-poll loop that floods notifications.
- Throttle startup failure notifications to at most one per 30 minutes per
room to prevent email/webhook storms during persistent failures.
- Reset backoff counter when a session successfully opens its first segment.
The ternary in GetLowStoragePauseMessageAsync had its branches swapped:
when storage was healthy it returned the pause error, and when storage
was critically low it returned null (allowing finalization to proceed).
This caused MP4 finalization to always pause with a misleading 'storage
is Red' warning even when storage protection was disabled.
API and nginx services now pull from reg.nxsir.cn/live_recorder
instead of building locally. The 'build' sections referenced the old
Dockerfiles with WSL-specific binfmt/proxy workarounds; the CI pipeline
in Jenkinsfile now handles multi-arch builds and pushes.
Uses patchable REGISTRY_URL env var (defaults to reg.nxsir.cn).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frontend Dockerfile was missing HTTP_PROXY/HTTPS_PROXY ARG declarations
in the build stage, so npm ci could not reach the npm registry through the
builder's proxy. Same fix pattern as the API Dockerfile.
This explains why the Web image has never been successfully built — the
pipeline always skips 'Build Web' after 'Build API' fails, but once API
build succeeds, Web build would hit the same npm registry issue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The case statement that sets RID based on TARGETARCH runs in a /bin/sh
subshell. When it was in a separate RUN from dotnet restore/publish,
the RID variable was not available to the publish command.
Merge the case dispatch, dotnet restore, and dotnet publish into a
single RUN so the RID shell variable stays in scope. Also restores
the COPY . . directive that was accidentally dropped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The previous inline case statement was missing proper variable assignment.
Use 'case' to set DOTNET_RID directly instead of trying to capture output
of a command substitution that contained a multi-branch case.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removing RuntimeIdentifier from the csproj caused dotnet publish to produce
ALL platform runtimes (20+) in the output, making runtime loading ambiguous
and causing FileLoadException at startup.
Instead of hardcoding the RID in the csproj, use Docker's built-in TARGETARCH
ARG (injected automatically by buildx for multi-platform builds):
amd64 -> -r linux-x64
arm64 -> -r linux-arm64
This ensures native deps (SQLitePCLRaw, EF Core) resolve to exactly one
architecture per image, while keeping the csproj clean for local dev.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docker driver only supports a single instance. Creating another fails with
'additional instances of driver docker cannot be created'. Just use the
default builder that ships with the docker daemon.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The docker-container driver requires moby/buildkit:buildx-stable-1 from
Docker Hub, which is unreachable from the build network (EOF / timeout).
The docker driver runs buildkit inside the host daemon without needing
a separate container image.
Also explicitly rm + recreate the builder each run so stale
docker-container instances don't linger as the default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removing <RuntimeIdentifier> from the csproj changed the publish layout,
but the old registry build cache still contains the RID-poisoned layers.
Subsequent builds cached at the COPY/RUN layer boundary reuse those stale
layers, causing FileLoadException at runtime.
Add --no-cache to both API and Web buildx invocations so every build
produces fresh layers. Once the pipeline stabilizes, we can re-enable
cache-from with the updated cache tag.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
:latest manifests already exist from the first successful run (build 123),
so subsequent docker manifest create without --amend fails with
'refusing to amend an existing manifest list'. Add --amend so every
pipeline run can update the :latest tag.
Also remove DEBUG config.json prints now that the auth path is verified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The csproj had <RuntimeIdentifier>linux-arm64</RuntimeIdentifier> baked in,
which forced dotnet publish to produce linux-arm64 native output on EVERY
platform (including amd64). On amd64 containers the runtime could not load
the entry assembly, causing FileLoadException crash loops.
RID is unnecessary for framework-dependent builds (--p:UseAppHost=false
is already in the Dockerfile). Removing it lets each platform produce
its natural runtime output — the base dotnet/aspnet image already has
the correct architecture's runtime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nuget.org is only reachable through the 7890 proxy from the build network
(direct hits return a 302 redirect loop; proxied requests return 200,
verified 8/8). The pipeline passes --build-arg HTTP_PROXY/HTTPS_PROXY, but
Dockerfile did not declare these ARGs in the build stage, so buildkit did
not inject them into the RUN environment and 'dotnet restore' tried nuget.org
directly -> NU1301 'Unable to load the service index'.
Declare HTTP_PROXY/HTTPS_PROXY/NO_PROXY (upper+lower case) as build-stage
ARGs and promote them to ENV so dotnet's HttpClient uses the proxy. Also add
two restore retries (--disable-parallel) to smooth over transient proxy
blips.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Harbor project is named 'live_recorder' (with underscore), matching
the robot account robot$live_recorder+live. The pipeline was pushing to
'liverecorder' (no underscore) — a different/nonexistent project path —
so the robot's push permission did not apply and every push got 401
despite 'Login Succeeded'.
This was THE root cause of the persistent 401s, not buildx auth
forwarding or token expiry (those were all red herrings).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every variant of docker login (--password-stdin, -p) has shown
'Login Succeeded' but docker push consistently gets 401.
Write the base64-encoded user:pass directly into
/root/.docker/config.json, eliminating docker login as a
variable entirely. If push still 401s after this, the problem
is definitively on the Harbor side (robot permissions).
Also fixes broken heredoc escaping from previous commit where
<<'DOCKERCFG' prevented shell variable expansion of AUTH_B64.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Suspect that echo + pipe to --password-stdin may be mangling the Jenkins
masked password variable. Switch to -p (command-line password) for a
cleaner auth path and add debug output to inspect /root/.docker/config.json
after login.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docker push is also getting 401 (not just buildx --push), suggesting
the Harbor login token expires during long builds or there is a
credential propagation gap between the standalone Login stage and the
build stages.
Move withCredentials into each build stage and re-login immediately
before every docker push / manifest push. This gives each push
operation a fresh token.
Pipeline is now: Checkout -> Prepare Buildx -> Build API (login + build
+ push + manifest) -> Build Web (same).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
buildx build --push has failed 401 on every attempt. The buildkit auth
forwarding (whether via docker-container or docker driver) does not work
reliably on this builder.
New strategy: build each platform separately with --load (into local
docker, which can read /root/.docker/config.json), then push with
native docker push, then assemble a multi-arch manifest with
docker manifest create/push.
Per-platform tags are pushed as :<BUILD_ID>-amd64 / :<BUILD_ID>-arm64
and the manifest combines them under the canonical :<BUILD_ID> and :latest.
This replaces a single buildx --push call with:
1. buildx build --platform linux/amd64 --load
2. docker push (amd64)
3. docker rmi (free disk)
4. buildx build --platform linux/arm64 --load
5. docker push (arm64)
6. docker rmi (free disk)
7. docker manifest create + push (multi-arch)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The docker-container driver runs buildkit in a separate container that
cannot reliably forward host Docker registry credentials via the buildx
session mechanism, causing every --push to fail with 401 Unauthorized.
The --auth flag doesn't exist in buildx 0.23.0 on this builder.
Fix: switch to 'docker' driver which runs buildkit inside the host
Docker daemon and naturally shares its registry auth state.
Changes:
- Login Registry stage restored (before Prepare Buildx)
- Prepare Buildx: driver docker (not docker-container), no driver-opts
- Build stages: stripped withCredentials wrappers and --auth flags
- Removed buildkitd.toml max-parallelism config (docker driver doesn't
support it; swap provides the safety net for OOM)
Pipeline flow: Checkout -> Login -> Prepare Buildx -> Build API -> Build Web
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>