mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-11 03:13:46 +00:00
feat(renderer): deploy the renderer next to the bot in compose
The bot now reaches the renderer at http://renderer:3000/api/gif on the compose network instead of a separately deployed service. Both share WHEELOFNAMES_API_TOKEN. CI runs the renderer's lint, typecheck, tests, render smoke, and image build.
This commit is contained in:
1 parent
de46809c96
commit
2bb5108151
12 files changed
+84
-63
No files matched your search
@@ -6,3 +6,4 @@ docs
|
|||||||
LICENSE
|
LICENSE
|
||||||
Dockerfile
|
Dockerfile
|
||||||
.dockerignore
|
.dockerignore
|
||||||
|
renderer
|
||||||
@@ -63,3 +63,40 @@ jobs:
|
|||||||
|
|
||||||
- name: docker build
|
- name: docker build
|
||||||
run: docker build -t miti99bot .
|
run: docker build -t miti99bot .
|
||||||
|
|
||||||
|
renderer:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: renderer
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: renderer/package-lock.json
|
||||||
|
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run lint
|
||||||
|
- run: npm run typecheck
|
||||||
|
- run: npm test
|
||||||
|
|
||||||
|
- name: Install Remotion browser runtime libraries
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
libnspr4 \
|
||||||
|
libnss3 \
|
||||||
|
libgtk-3-0 \
|
||||||
|
libgbm1 \
|
||||||
|
libasound2t64 \
|
||||||
|
libxshmfence1 \
|
||||||
|
fonts-noto
|
||||||
|
- run: npm run browser:ensure
|
||||||
|
- run: npm run render:smoke
|
||||||
|
- run: npm run api:smoke
|
||||||
|
|
||||||
|
- name: docker build
|
||||||
|
run: docker build -t miti99bot-renderer .
|
||||||
+31
-2
@@ -14,8 +14,12 @@ services:
|
|||||||
MODULES: ${MODULES} # CSV; empty = all modules
|
MODULES: ${MODULES} # CSV; empty = all modules
|
||||||
OWNER_ID: ${OWNER_ID} # Telegram user id for owner-only commands
|
OWNER_ID: ${OWNER_ID} # Telegram user id for owner-only commands
|
||||||
ADMIN_IDS: ${ADMIN_IDS} # CSV of admin Telegram user ids
|
ADMIN_IDS: ${ADMIN_IDS} # CSV of admin Telegram user ids
|
||||||
WHEELOFNAMES_API_URL: ${WHEELOFNAMES_API_URL:-} # Optional full /api/gif endpoint (/gacha uses /api/gacha)
|
# The bundled renderer service below draws /wheelofnames, /gacha and
|
||||||
WHEELOFNAMES_API_TOKEN: ${WHEELOFNAMES_API_TOKEN:-} # Optional bearer token for that service
|
# /genshin. The URL is fixed to its in-network address so a stale
|
||||||
|
# platform-level value cannot point the bot elsewhere; /gacha and
|
||||||
|
# /genshin derive their endpoints from it.
|
||||||
|
WHEELOFNAMES_API_URL: http://renderer:3000/api/gif
|
||||||
|
WHEELOFNAMES_API_TOKEN: ${WHEELOFNAMES_API_TOKEN:-} # Shared bearer token; the renderer uses it as API_TOKEN
|
||||||
# SOURCE_COMMIT is intentionally not declared here. Coolify provides it
|
# SOURCE_COMMIT is intentionally not declared here. Coolify provides it
|
||||||
# at runtime via its generated env file; declaring it here with Compose
|
# at runtime via its generated env file; declaring it here with Compose
|
||||||
# interpolation can override the runtime value with an empty string.
|
# interpolation can override the runtime value with an empty string.
|
||||||
@@ -37,3 +41,28 @@ services:
|
|||||||
# defined here. Configure that monitor against GET / instead
|
# defined here. Configure that monitor against GET / instead
|
||||||
# (returns text/plain "miti99bot ok"). Note: a plain / check does not verify
|
# (returns text/plain "miti99bot ok"). Note: a plain / check does not verify
|
||||||
# Mongo connectivity — see docs/deploy-coolify-selfhosted.md.
|
# Mongo connectivity — see docs/deploy-coolify-selfhosted.md.
|
||||||
|
|
||||||
|
# Animation renderer (Node + Remotion + headless Chrome) from renderer/.
|
||||||
|
# Internal only: the bot reaches it over the compose network, so it has no
|
||||||
|
# published port and no public domain. Without WHEELOFNAMES_API_TOKEN it
|
||||||
|
# refuses to start in production, and the bot falls back to text replies.
|
||||||
|
renderer:
|
||||||
|
build:
|
||||||
|
context: ./renderer
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
HOST: 0.0.0.0
|
||||||
|
PORT: "3000"
|
||||||
|
API_TOKEN: ${WHEELOFNAMES_API_TOKEN:-}
|
||||||
|
MAX_CONCURRENT_RENDERS: ${MAX_CONCURRENT_RENDERS:-1}
|
||||||
|
RENDER_TIMEOUT_MS: ${RENDER_TIMEOUT_MS:-15000}
|
||||||
|
MAX_OPTIONS: ${MAX_OPTIONS:-32}
|
||||||
|
MAX_OPTION_CHARS: ${MAX_OPTION_CHARS:-40}
|
||||||
|
expose:
|
||||||
|
- "3000"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/api/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Vendored
-34
@@ -1,34 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: npm
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run lint
|
|
||||||
- run: npm run typecheck
|
|
||||||
- run: npm test
|
|
||||||
- name: Install Remotion browser runtime libraries
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
libnspr4 \
|
|
||||||
libnss3 \
|
|
||||||
libgtk-3-0 \
|
|
||||||
libgbm1 \
|
|
||||||
libasound2t64 \
|
|
||||||
libxshmfence1 \
|
|
||||||
fonts-noto
|
|
||||||
- run: npm run browser:ensure
|
|
||||||
- run: npm run render:smoke
|
|
||||||
- run: npm run api:smoke
|
|
||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
# wheelofnames
|
# renderer
|
||||||
|
|
||||||
|
Part of miti99bot: the service behind `/wheelofnames`, `/gacha`, and
|
||||||
|
`/genshin`, deployed by the root `compose.yml` as the `renderer` service.
|
||||||
Self-hosted API that renders wheel-of-names GIF animations and Genshin-style
|
Self-hosted API that renders wheel-of-names GIF animations and Genshin-style
|
||||||
meteor wish MP4 animations with Remotion, and card-pack gacha wish MP4
|
meteor wish MP4 animations with Remotion, and card-pack gacha wish MP4
|
||||||
animations with pack-cards.
|
animations with pack-cards.
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
services:
|
|
||||||
wheelofnames:
|
|
||||||
build: .
|
|
||||||
environment:
|
|
||||||
NODE_ENV: "${NODE_ENV:-production}"
|
|
||||||
HOST: "${HOST:-0.0.0.0}"
|
|
||||||
PORT: "${PORT:-3000}"
|
|
||||||
API_TOKEN: "${API_TOKEN:-change-me}"
|
|
||||||
MAX_CONCURRENT_RENDERS: "${MAX_CONCURRENT_RENDERS:-1}"
|
|
||||||
RENDER_TIMEOUT_MS: "${RENDER_TIMEOUT_MS:-15000}"
|
|
||||||
MAX_OPTIONS: "${MAX_OPTIONS:-32}"
|
|
||||||
MAX_OPTION_CHARS: "${MAX_OPTION_CHARS:-40}"
|
|
||||||
# Coolify routes to the container port over its proxy network, so the host
|
|
||||||
# port stays unpublished there. Uncomment for a standalone `docker compose up`.
|
|
||||||
# ports:
|
|
||||||
# - "${PORT:-3000}:${PORT:-3000}"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:${PORT:-3000}/api/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
# Deployment
|
# Deployment
|
||||||
|
|
||||||
|
## miti99bot compose
|
||||||
|
|
||||||
|
The root `compose.yml` builds this folder as the `renderer` service and points
|
||||||
|
the bot at it over the compose network. Only `WHEELOFNAMES_API_TOKEN` needs a
|
||||||
|
value there; it becomes `API_TOKEN` below. The rest of this page covers running
|
||||||
|
the service on its own.
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Use a self-hosted/container runtime for v1. Static-only hosts are not enough
|
Use a self-hosted/container runtime for v1. Static-only hosts are not enough
|
||||||
@@ -33,8 +40,8 @@ MAX_OPTION_CHARS=40
|
|||||||
API_TOKEN=change-me
|
API_TOKEN=change-me
|
||||||
```
|
```
|
||||||
|
|
||||||
`compose.yml` forwards these values from the shell with `${VAR:-default}`
|
The root `compose.yml` forwards the tuning values with `${VAR:-default}`
|
||||||
fallbacks, so unset or empty shell variables use the defaults above.
|
fallbacks, so unset or empty variables use the defaults above.
|
||||||
|
|
||||||
Start with 1-2 vCPU and 1-2 GB RAM. Increase only after render benchmarks show
|
Start with 1-2 vCPU and 1-2 GB RAM. Increase only after render benchmarks show
|
||||||
the service is CPU-bound or concurrency-limited.
|
the service is CPU-bound or concurrency-limited.
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "wheelofnames",
|
"name": "miti99bot-renderer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "wheelofnames",
|
"name": "miti99bot-renderer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remotion/bundler": "4.0.485",
|
"@remotion/bundler": "4.0.485",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "wheelofnames",
|
"name": "miti99bot-renderer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
Reference in new issue
Block a user