Merge pull request #11 from Danya-Djan/issue/6

Various fixes
This commit is contained in:
Michail Kostocka 2024-12-17 14:20:29 +03:00 committed by GitHub
commit 3c8cd2872a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 99 additions and 235 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ celerybeat-schedule
backend/static backend/static
backend/media backend/media
bot/logs.log bot/logs.log
bot/logfile.log

View File

@ -1,22 +1,7 @@
FROM python:3.11 FROM python:3.11
# python envs COPY . /app
ENV PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100
# python dependencies RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./requirements.txt /
RUN pip install -r ./requirements.txt
COPY ./scripts/entrypoint.sh ./scripts/start.sh ./scripts/gunicorn.sh ./scripts/start_celery.sh /
# upload scripts
# Fix windows docker bug, convert CRLF to LF
RUN sed -i 's/\r$//g' /start.sh && chmod +x /start.sh && sed -i 's/\r$//g' /entrypoint.sh && chmod +x /entrypoint.sh &&\
sed -i 's/\r$//g' /gunicorn.sh && chmod +x /gunicorn.sh && sed -i 's/\r$//g' /start_celery.sh && chmod +x /start_celery.sh
WORKDIR /app WORKDIR /app

View File

@ -1,32 +0,0 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
cmd="$@"
function postgres_ready(){
python << END
import sys
import os
import psycopg2
try:
dbname = os.getenv('POSTGRES_DB')
user = os.getenv('POSTGRES_USER')
password = os.getenv('POSTGRES_PASSWORD')
host = os.getenv('DB_HOST', 'postgres')
port = os.getenv('POSTGRES_PORT', '5432')
conn = psycopg2.connect(dbname=dbname, user=user, password=password, host=host, port=port)
except psycopg2.OperationalError:
sys.exit(-1)
sys.exit(0)
END
}
until postgres_ready; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - continuing..."
exec $cmd

0
backend/scripts/gunicorn.sh Normal file → Executable file
View File

0
backend/scripts/start.sh Normal file → Executable file
View File

8
backend/scripts/start_celery.sh Normal file → Executable file
View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/bin/sh
for i in {0..$CELERY_WORKER_COUNT} for i in $(seq 1 "${CELERY_WORKER_COUNT}"); do
do celery -A clicker worker -l info --concurrency=10 -n "worker${i}@$(%h)"
celery -A clicker worker -l info --concurrency=10 -n worker$i@%h
done done
celery -A clicker beat -l info

View File

@ -2,12 +2,10 @@ FROM python:3.12
WORKDIR /batcher WORKDIR /batcher
COPY ./requirements.txt /batcher/requirements.txt COPY ./ /batcher
RUN pip install --no-cache-dir --upgrade -r /batcher/requirements.txt RUN pip install --no-cache-dir --upgrade -r /batcher/requirements.txt
COPY ./app /batcher/app
ENV PYTHONPATH="${PYTHONPATH}:/batcher/app" ENV PYTHONPATH="${PYTHONPATH}:/batcher/app"
CMD uvicorn app.main:app --host 0.0.0.0 --port "${HTTP_PORT}" CMD uvicorn app.main:app --host 0.0.0.0 --port "${HTTP_PORT}"

View File

@ -15,14 +15,7 @@ MIGRATIONS_DIR = Path(__file__).parent.resolve() / "migrations"
logger = logging.getLogger("uvicorn") logger = logging.getLogger("uvicorn")
async def connect_pg() -> asyncpg.Pool: async def connect_pg() -> asyncpg.Pool:
while True: return await asyncpg.create_pool(DB_URL)
try:
logger.info(DB_URL)
pg_conn = await asyncpg.create_pool(DB_URL)
return pg_conn
except OSError:
logger.info("Postgres is unavailable - sleeping")
await asyncio.sleep(2)
async def get_pg(request: Request) -> asyncpg.Connection: async def get_pg(request: Request) -> asyncpg.Connection:

View File

@ -11,13 +11,7 @@ fqdn = f'amqp://{RMQ_USER}:{str(RMQ_PASSWORD)}@{RMQ_HOST}:{RMQ_PORT}/'
logger = logging.getLogger("uvicorn") logger = logging.getLogger("uvicorn")
async def get_connection() -> AbstractRobustConnection: async def get_connection() -> AbstractRobustConnection:
while True: return await aio_pika.connect_robust(fqdn)
try:
conn = await aio_pika.connect_robust(fqdn)
return conn
except ConnectionError:
logger.info("RabbitMQ is unavailable - sleeping")
await asyncio.sleep(2)
async def get_channel(conn_pool: AbstractRobustConnection) -> aio_pika.Channel: async def get_channel(conn_pool: AbstractRobustConnection) -> aio_pika.Channel:

View File

@ -1,21 +1,7 @@
FROM python:3.10.7 FROM python:3.11
# python envs COPY . /app
ENV PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100
# python dependencies
COPY ./requirements.txt /
RUN pip install -r /requirements.txt
COPY ./scripts/start.sh ./scripts/gunicorn.sh /
RUN chmod +x /start.sh
RUN chmod +x /gunicorn.sh
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
WORKDIR /app WORKDIR /app

View File

@ -8,7 +8,7 @@ from aiogram.dispatcher.filters.state import State, StatesGroup
from create_bot import bot, important_message, event_number from create_bot import bot, important_message, event_number
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.utils.exceptions import MessageToDeleteNotFound from aiogram.utils.exceptions import MessageToDeleteNotFound
from bot.dbm_defs import add_rec, get_rec from dbm_defs import add_rec, get_rec
from loguru import logger from loguru import logger

0
bot/scripts/gunicorn.sh Normal file → Executable file
View File

0
bot/scripts/start.sh Normal file → Executable file
View File

View File

@ -2,20 +2,23 @@ volumes:
db_data: {} db_data: {}
batcher_db_data: {} batcher_db_data: {}
redis_data: {} redis_data: {}
backend_media: {}
certbot_www: {}
certbot_conf: {}
services: services:
backend: backend:
build: build:
context: ./backend context: ./backend
volumes: volumes:
- ./backend:/app - backend_media:/app/media
command: /gunicorn.sh command: /app/scripts/gunicorn.sh
entrypoint: /entrypoint.sh
restart: on-failure restart: on-failure
depends_on: depends_on:
- postgres postgres: &healthy-dependency
- rabbitmq condition: service_healthy
env_file: rabbitmq: *healthy-dependency
env_file: &backend-env-files
- .env/prod/pg - .env/prod/pg
- .env/prod/back - .env/prod/back
- .env/prod/rmq - .env/prod/rmq
@ -23,29 +26,33 @@ services:
- .env/prod/web - .env/prod/web
bot: bot:
build: build: ./bot
context: ./bot
depends_on: depends_on:
- backend backend: &started-dependency
volumes: condition: service_started
- ./bot:/app batcher: *started-dependency
environment: memcached: *started-dependency
PROD: 1
env_file: env_file:
- .env/prod/bot - .env/prod/bot
- .env/prod/web - .env/prod/web
command: /gunicorn.sh command: /app/scripts/gunicorn.sh
restart: on-failure restart: on-failure
memcached: memcached:
image: memcached:latest image: memcached:latest
postgres: postgres: &pg-conf
image: postgres:14.5-alpine image: postgres:17-alpine
volumes: volumes:
- db_data:/var/lib/postgresql/data - db_data:/var/lib/postgresql/data
env_file: env_file:
- .env/prod/pg - .env/prod/pg
user: postgres
healthcheck: &pg-healthcheck
test: [ "CMD-SHELL", "pg_isready" ]
interval: 5s
timeout: 2s
retries: 5
nginx: nginx:
build: build:
@ -55,61 +62,30 @@ services:
- '80:80' - '80:80'
- '443:443' - '443:443'
depends_on: depends_on:
- backend bot: *started-dependency
- bot
- rabbitmq
- batcher
volumes: volumes:
- ./backend/static/:/static/ - ./backend/static/:/static/
- ./nginx/certbot/conf:/etc/letsencrypt
- ./nginx/certbot/www:/var/www/certbot
restart: unless-stopped restart: unless-stopped
command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"'''
certbot:
container_name: certbot
image: certbot/certbot
volumes:
- ./nginx/certbot/conf:/etc/letsencrypt
- ./nginx/certbot/www:/var/www/certbot
restart: unless-stopped
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
celery: celery:
build: ./backend build: ./backend
command: /start_celery.sh command: /app/scripts/start_celery.sh
volumes: env_file: *backend-env-files
- ./backend:/app environment:
env_file: - CELERY_WORKER_COUNT=10
- .env/prod/back
- .env/prod/rmq
- .env/prod/pg
- .env/prod/bot
depends_on: depends_on:
- backend backend: *started-dependency
- rabbitmq
celery-beat:
build: ./backend
command: celery -A clicker beat -l info
volumes:
- ./backend:/app
env_file:
- .env/prod/back
- .env/prod/rmq
- .env/prod/pg
- .env/prod/bot
depends_on:
- backend
- rabbitmq
rabbitmq: rabbitmq:
container_name: 'rabbitmq' container_name: 'rabbitmq'
image: 'rabbitmq:3-management-alpine' image: 'rabbitmq:3-management-alpine'
env_file: env_file:
- .env/prod/rmq - .env/prod/rmq
ports: healthcheck:
- '15672:15672' <<: *pg-healthcheck
test: rabbitmq-diagnostics -q ping
interval: 10s
timeout: 2s
redis: redis:
env_file: env_file:
@ -118,14 +94,16 @@ services:
command: bash -c "redis-server --appendonly yes --requirepass $${REDIS_PASSWORD}" command: bash -c "redis-server --appendonly yes --requirepass $${REDIS_PASSWORD}"
volumes: volumes:
- redis_data:/data - redis_data:/data
healthcheck:
<<: *pg-healthcheck
test: "[ $$(redis-cli -a $${REDIS_PASSWORD} ping) = 'PONG' ]"
batcher: batcher:
build: build: ./batcher
context: ./batcher
depends_on: depends_on:
- redis redis: *healthy-dependency
- batcher-postgres batcher-postgres: *healthy-dependency
- rabbitmq rabbitmq: *healthy-dependency
env_file: env_file:
- .env/prod/rmq - .env/prod/rmq
- .env/prod/redis - .env/prod/redis
@ -134,7 +112,7 @@ services:
- .env/prod/bot - .env/prod/bot
batcher-postgres: batcher-postgres:
image: postgres:14.5-alpine <<: *pg-conf
volumes: volumes:
- batcher_db_data:/var/lib/postgresql/data - batcher_db_data:/var/lib/postgresql/data
env_file: env_file:

View File

@ -2,20 +2,20 @@ volumes:
db_data: {} db_data: {}
batcher_db_data: {} batcher_db_data: {}
redis_data: {} redis_data: {}
backend_media: {}
services: services:
backend: backend:
build: build: ./backend
context: ./backend
depends_on: depends_on:
- postgres postgres: &healthy-dependency
- rabbitmq condition: service_healthy
rabbitmq: *healthy-dependency
volumes: volumes:
- ./backend:/app - backend_media:/app/media
command: /start.sh command: /app/scripts/start.sh
entrypoint: /entrypoint.sh
restart: on-failure restart: on-failure
env_file: env_file: &backend-env-files
- .env/dev/pg - .env/dev/pg
- .env/dev/back - .env/dev/back
- .env/dev/rmq - .env/dev/rmq
@ -24,44 +24,31 @@ services:
ports: ports:
- '8000:8000' - '8000:8000'
postgres: postgres: &pg-conf
image: postgres:14.5-alpine image: postgres:17-alpine
volumes: volumes:
- db_data:/var/lib/postgresql/data - db_data:/var/lib/postgresql/data
env_file: env_file:
- .env/dev/pg - .env/dev/pg
ports: ports:
- '5432:5432' - '5432:5432'
user: postgres
healthcheck: &pg-healthcheck
test: [ "CMD-SHELL", "pg_isready" ]
interval: 5s
timeout: 2s
retries: 5
celery: celery:
build: ./backend build: ./backend
command: celery -A clicker worker -l info command: /app/scripts/start_celery.sh
volumes: env_file: *backend-env-files
- ./backend:/app environment:
env_file: - CELERY_WORKER_COUNT=1
- .env/dev/back
- .env/dev/rmq
- .env/dev/pg
- .env/dev/bot
- .env/dev/web
depends_on: depends_on:
- backend backend:
- rabbitmq condition: service_started
rabbitmq: *healthy-dependency
celery-beat:
build: ./backend
command: celery -A clicker beat -l info
volumes:
- ./backend:/app
env_file:
- .env/dev/back
- .env/dev/rmq
- .env/dev/pg
- .env/dev/bot
- .env/dev/web
depends_on:
- backend
- rabbitmq
rabbitmq: rabbitmq:
container_name: 'rabbitmq' container_name: 'rabbitmq'
@ -71,6 +58,11 @@ services:
ports: ports:
- '5672:5672' - '5672:5672'
- '15672:15672' - '15672:15672'
healthcheck:
<<: *pg-healthcheck
test: rabbitmq-diagnostics -q ping
interval: 10s
timeout: 2s
redis: redis:
env_file: env_file:
@ -81,13 +73,16 @@ services:
- '6379:6379' - '6379:6379'
volumes: volumes:
- redis_data:/data - redis_data:/data
healthcheck:
<<: *pg-healthcheck
test: "[ $$(redis-cli -a $$REDIS_PASSWORD ping) = 'PONG' ]"
batcher: batcher:
build: build: ./batcher
context: ./batcher
depends_on: depends_on:
- redis redis: *healthy-dependency
- batcher-postgres batcher-postgres: *healthy-dependency
rabbitmq: *healthy-dependency
env_file: env_file:
- .env/dev/rmq - .env/dev/rmq
- .env/dev/redis - .env/dev/redis
@ -99,7 +94,7 @@ services:
- '8080:8080' - '8080:8080'
batcher-postgres: batcher-postgres:
image: postgres:14.5-alpine <<: *pg-conf
volumes: volumes:
- batcher_db_data:/var/lib/postgresql/data - batcher_db_data:/var/lib/postgresql/data
env_file: env_file:

View File

@ -13,7 +13,11 @@ RUN npm run build
# stage 2 - nginx # stage 2 - nginx
FROM nginx:stable FROM nginx:stable
COPY nginx/nginx.conf /etc/nginx/nginx.conf COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY backend/static /static
COPY --from=build-deps /app/dist/ /dist/ COPY --from=build-deps /app/dist/ /dist/
CMD ["nginx", "-g", "daemon off;"] CMD ["nginx", "-g", "daemon off;"]

View File

@ -42,33 +42,11 @@ http {
access_log /var/log/nginx/access.log upstreamlog; access_log /var/log/nginx/access.log upstreamlog;
error_log /var/log/nginx/error.log; error_log /var/log/nginx/error.log;
listen 80; listen 80;
# listen 443 ssl http2;
charset utf-8; charset utf-8;
# server_name kyc_clicker.ru www.kyc_clicker.ru;
root /dist/; root /dist/;
index index.html; index index.html;
# ssl_certificate /etc/letsencrypt/live/kyc_clicker.ru/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/kyc_clicker.ru/privkey.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# if ($server_port = 80) {
# set $https_redirect 1;
# }
# if ($host ~ '^www\.') {
# set $https_redirect 1;
# }
# if ($https_redirect = 1) {
# return 301 https://crowngame.ru$request_uri;
# }
# location /.well-known/acme-challenge/ {
# root /var/www/certbot;
# }
# frontend # frontend
location / { location / {
try_files $uri $uri/ @rewrites; try_files $uri $uri/ @rewrites;
@ -79,7 +57,8 @@ http {
} }
# batcher # batcher
location ~ ^/api/v1/(batch\-click|click|energy|coefficient)(/(.*))? { location ~ ^/api/v1/batcher(/?.*) {
rewrite ^(/api/v1)/batcher(/?.*)$ $1/$2 last;
proxy_pass http://batcher; proxy_pass http://batcher;
proxy_pass_header Authorization; proxy_pass_header Authorization;
} }
@ -98,29 +77,12 @@ http {
proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
if ($uri ~* \.(?:ico|js|css|gif|jpe?g|png|webp)/?$) {
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
} }
# bot # bot
location ~ ^/bot { location ~ ^/bot {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_pass http://bot; proxy_pass http://bot;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
} }
# backend static # backend static