mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-01-14 21:23:29 +01:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
448841dadc | ||
|
|
1b6934694e | ||
|
|
d4d00ba02f | ||
|
|
19a65ac45f | ||
|
|
b72e7bd707 | ||
|
|
190be3e813 | ||
|
|
88300b314c | ||
|
|
fab77c8d9f | ||
|
|
1ae7158d7e | ||
|
|
05f0356288 | ||
|
|
b3cea17b8d | ||
|
|
0b66b23f16 | ||
|
|
80fdf70f7d | ||
|
|
fa931b0db2 | ||
|
|
cab79b4203 | ||
|
|
ddab3db6b5 | ||
|
|
9fa704811c | ||
|
|
4c0d14def0 | ||
|
|
43382d2ffe | ||
|
|
27d448afd6 | ||
|
|
1dd90974bd | ||
|
|
31cc8db3ac | ||
|
|
3d85a15ec9 | ||
|
|
90f98c2d15 | ||
|
|
643855e60e | ||
|
|
e0f7b532f8 |
@@ -23,3 +23,5 @@ WEB_CONCURRENCY=4
|
||||
ENABLE_SOFT_DELETE=false
|
||||
# If ENABLE_SOFT_DELETE is true, transactions deleted for more than KEEP_DELETED_TRANSACTIONS_FOR days will be truly deleted. Set to 0 to keep all.
|
||||
KEEP_DELETED_TRANSACTIONS_FOR=365
|
||||
|
||||
TASK_WORKERS=1 # This only work if you're using the single container option. Increase to have more open queues via procrastinate, you probably don't need to increase this.
|
||||
|
||||
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@@ -3,6 +3,8 @@ name: Release Pipeline
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
IMAGE_NAME: wygiwyh
|
||||
@@ -29,7 +31,21 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push image
|
||||
- name: Build and push nightly image
|
||||
if: github.event_name == 'push'
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/prod/django/Dockerfile
|
||||
push: true
|
||||
provenance: false
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:nightly
|
||||
platforms: linux/amd64,linux/arm64
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build and push release image
|
||||
if: github.event_name == 'release'
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
|
||||
@@ -222,7 +222,7 @@ SESSION_COOKIE_SECURE = os.getenv("HTTPS_ENABLED", "false").lower() == "true"
|
||||
|
||||
DEBUG_TOOLBAR_CONFIG = {
|
||||
"ROOT_TAG_EXTRA_ATTRS": "hx-preserve",
|
||||
"SHOW_TOOLBAR_CALLBACK": lambda r: False, # disables it}
|
||||
# "SHOW_TOOLBAR_CALLBACK": lambda r: False, # disables it
|
||||
}
|
||||
DEBUG_TOOLBAR_PANELS = [
|
||||
"debug_toolbar.panels.history.HistoryPanel",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import logging
|
||||
|
||||
from asgiref.sync import sync_to_async
|
||||
from django.core import management
|
||||
|
||||
from procrastinate import builtin_tasks
|
||||
from procrastinate.contrib.django import app
|
||||
|
||||
@@ -24,3 +27,16 @@ async def remove_old_jobs(context, timestamp):
|
||||
exc_info=True,
|
||||
)
|
||||
raise e
|
||||
|
||||
|
||||
@app.periodic(cron="0 6 1 * *")
|
||||
@app.task(queueing_lock="remove_expired_sessions")
|
||||
async def remove_expired_sessions(timestamp=None):
|
||||
"""Cleanup expired sessions by using Django management command."""
|
||||
try:
|
||||
await sync_to_async(management.call_command)("clearsessions", verbosity=0)
|
||||
except Exception:
|
||||
logger.error(
|
||||
"Error while executing 'remove_expired_sessions' task",
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
@@ -65,7 +65,7 @@ class CSVImportSettings(BaseModel):
|
||||
|
||||
|
||||
class ColumnMapping(BaseModel):
|
||||
source: Optional[str] = Field(
|
||||
source: Optional[str] | Optional[list[str]] = Field(
|
||||
default=None,
|
||||
description="CSV column header. If None, the field will be generated from transformations",
|
||||
)
|
||||
|
||||
@@ -486,8 +486,18 @@ class ImportService:
|
||||
mapped_data = {}
|
||||
|
||||
for field, mapping in self.mapping.items():
|
||||
# If source is None, use None as the initial value
|
||||
value = row.get(mapping.source) if mapping.source else None
|
||||
value = None
|
||||
|
||||
if isinstance(mapping.source, str):
|
||||
value = row.get(mapping.source)
|
||||
elif isinstance(mapping.source, list):
|
||||
for source in mapping.source:
|
||||
value = row.get(source)
|
||||
if value is not None:
|
||||
break
|
||||
else:
|
||||
# If source is None, use None as the initial value
|
||||
value = None
|
||||
|
||||
# Use default_value if value is None
|
||||
if value is None:
|
||||
|
||||
@@ -30,6 +30,8 @@ def index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def monthly_overview(request, month: int, year: int):
|
||||
order = request.session.get("monthly_transactions_order", "default")
|
||||
|
||||
if month < 1 or month > 12:
|
||||
from django.http import Http404
|
||||
|
||||
@@ -54,6 +56,7 @@ def monthly_overview(request, month: int, year: int):
|
||||
"previous_month": previous_month,
|
||||
"previous_year": previous_year,
|
||||
"filter": f,
|
||||
"order": order,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -62,7 +65,12 @@ def monthly_overview(request, month: int, year: int):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def transactions_list(request, month: int, year: int):
|
||||
order = request.GET.get("order")
|
||||
order = request.session.get("monthly_transactions_order", "default")
|
||||
|
||||
if "order" in request.GET:
|
||||
order = request.GET["order"]
|
||||
if order != request.session["monthly_transactions_order"]:
|
||||
request.session["monthly_transactions_order"] = order
|
||||
|
||||
f = TransactionsFilter(request.GET)
|
||||
transactions_filtered = (
|
||||
|
||||
@@ -313,15 +313,23 @@ def transaction_pay(request, transaction_id):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def transaction_all_index(request):
|
||||
order = request.session.get("all_transactions_order", "default")
|
||||
f = TransactionsFilter(request.GET)
|
||||
return render(request, "transactions/pages/transactions.html", {"filter": f})
|
||||
return render(
|
||||
request, "transactions/pages/transactions.html", {"filter": f, "order": order}
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def transaction_all_list(request):
|
||||
order = request.GET.get("order")
|
||||
order = request.session.get("all_transactions_order", "default")
|
||||
|
||||
if "order" in request.GET:
|
||||
order = request.GET["order"]
|
||||
if order != request.session["all_transactions_order"]:
|
||||
request.session["all_transactions_order"] = order
|
||||
|
||||
transactions = Transaction.objects.prefetch_related(
|
||||
"account",
|
||||
|
||||
2319
app/locale/de/LC_MESSAGES/django.po
Normal file
2319
app/locale/de/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -39,23 +39,23 @@
|
||||
{% for transaction in date.transactions %}
|
||||
{% if transaction.is_paid %}
|
||||
{% if transaction.type == "IN" and not transaction.account.is_asset %}
|
||||
<i class="fa-solid fa-circle-check tw-text-green-400" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-solid fa-circle-check tw-text-green-400" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
|
||||
{% elif transaction.type == "IN" and transaction.account.is_asset %}
|
||||
<i class="fa-solid fa-circle-check tw-text-green-300" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-solid fa-circle-check tw-text-green-300" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
|
||||
{% elif transaction.type == "EX" and not transaction.account.is_asset %}
|
||||
<i class="fa-solid fa-circle-check tw-text-red-400" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-solid fa-circle-check tw-text-red-400" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
|
||||
{% elif transaction.type == "EX" and transaction.account.is_asset %}
|
||||
<i class="fa-solid fa-circle-check tw-text-red-300" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-solid fa-circle-check tw-text-red-300" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if transaction.type == "IN" and not transaction.account.is_asset %}
|
||||
<i class="fa-regular fa-circle tw-text-green-400" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-regular fa-circle tw-text-green-400" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
|
||||
{% elif transaction.type == "IN" and transaction.account.is_asset %}
|
||||
<i class="fa-regular fa-circle tw-text-green-300" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-regular fa-circle tw-text-green-300" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
|
||||
{% elif transaction.type == "EX" and not transaction.account.is_asset %}
|
||||
<i class="fa-regular fa-circle tw-text-red-400" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-regular fa-circle tw-text-red-400" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
|
||||
{% elif transaction.type == "EX" and transaction.account.is_asset %}
|
||||
<i class="fa-regular fa-circle tw-text-green-300" data-bs-toggle="tooltip" data-bs-title="{{ transaction.description }}"></i>
|
||||
<i class="fa-regular fa-circle tw-text-red-300" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
{% block title %}{% translate 'Transactions on' %} {{ date|date:"SHORT_DATE_FORMAT" }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div hx-get="{% url 'calendar_transactions_list' day=date.day month=date.month year=date.year %}" hx-trigger="updated from:window" hx-vals='{"disable_selection": true}' hx-target="closest .offcanvas" class="show-loading">
|
||||
{% for transaction in transactions %}
|
||||
<c-transaction.item
|
||||
:transaction="transaction"
|
||||
:disable-selection="True"></c-transaction.item>
|
||||
{% empty %}
|
||||
<c-msg.empty
|
||||
title="{% translate 'No transactions on this date' %}"></c-msg.empty>
|
||||
{% endfor %}
|
||||
<div hx-get="{% url 'calendar_transactions_list' day=date.day month=date.month year=date.year %}" hx-trigger="updated from:window" hx-vals='{"disable_selection": true}' hx-target="closest .offcanvas" class="show-loading" id="transactions-list">
|
||||
{% for transaction in transactions %}
|
||||
<c-transaction.item :transaction="transaction"></c-transaction.item>
|
||||
{% empty %}
|
||||
<c-msg.empty
|
||||
title="{% translate 'No transactions on this date' %}"></c-msg.empty>
|
||||
{% endfor %}
|
||||
{# Floating bar #}
|
||||
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
{% block title %}{% translate 'Installments' %}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div hx-get="{% url 'installment_plan_transactions' installment_plan_id=installment_plan.id %}" hx-trigger="updated from:window" hx-vals='{"disable_selection": true}' hx-target="closest .offcanvas" class="show-loading">
|
||||
{% for transaction in transactions %}
|
||||
<c-transaction.item
|
||||
:transaction="transaction"
|
||||
:disable-selection="True"></c-transaction.item>
|
||||
{% endfor %}
|
||||
<div hx-get="{% url 'installment_plan_transactions' installment_plan_id=installment_plan.id %}" hx-trigger="updated from:window" hx-vals='{"disable_selection": true}' hx-target="closest .offcanvas" class="show-loading" id="transactions-list">
|
||||
{% for transaction in transactions %}
|
||||
<c-transaction.item :transaction="transaction"></c-transaction.item>
|
||||
{% endfor %}
|
||||
{# Floating bar #}
|
||||
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
<div id="content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
{% include 'includes/toasts.html' %}
|
||||
|
||||
{% include 'includes/scripts.html' %}
|
||||
{% block extra_js %}{% endblock %}
|
||||
|
||||
@@ -113,9 +113,9 @@
|
||||
<div class="text-sm-end" _="on change trigger updated on window">
|
||||
<label for="order">{% translate "Order by" %}</label>
|
||||
<select class="tw-border-0 focus-visible:tw-outline-0 w-full pe-2 tw-leading-normal text-bg-tertiary tw-font-medium rounded" name="order" id="order">
|
||||
<option value="default">{% translate 'Default' %}</option>
|
||||
<option value="older">{% translate 'Oldest first' %}</option>
|
||||
<option value="newer">{% translate 'Newest first' %}</option>
|
||||
<option value="default" {% if order == 'default' %}selected{% endif %}>{% translate 'Default' %}</option>
|
||||
<option value="older" {% if order == 'older' %}selected{% endif %}>{% translate 'Oldest first' %}</option>
|
||||
<option value="newer" {% if order == 'newer' %}selected{% endif %}>{% translate 'Newest first' %}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
{% block title %}{% translate 'Transactions' %}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div hx-get="{% url 'recurring_transaction_transactions' recurring_transaction_id=recurring_transaction.id %}" hx-trigger="updated from:window" hx-vals='{"disable_selection": true}' hx-target="closest .offcanvas" class="show-loading">
|
||||
{% for transaction in transactions %}
|
||||
<c-transaction.item
|
||||
:transaction="transaction"
|
||||
:disable-selection="True"></c-transaction.item>
|
||||
{% endfor %}
|
||||
<div hx-get="{% url 'recurring_transaction_transactions' recurring_transaction_id=recurring_transaction.id %}" hx-trigger="updated from:window" hx-vals='{"disable_selection": true}' hx-target="closest .offcanvas" class="show-loading" id="transactions-list">
|
||||
{% for transaction in transactions %}
|
||||
<c-transaction.item :transaction="transaction"></c-transaction.item>
|
||||
{% endfor %}
|
||||
{# Floating bar #}
|
||||
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
<div class="tw-content-center" _="on change trigger updated on window">
|
||||
<label for="order">{% translate "Order by" %}</label>
|
||||
<select class="tw-border-0 focus-visible:tw-outline-0 w-full pe-2 tw-leading-normal text-bg-tertiary tw-font-medium rounded" name="order" id="order">
|
||||
<option value="default">{% translate 'Default' %}</option>
|
||||
<option value="older">{% translate 'Oldest first' %}</option>
|
||||
<option value="newer">{% translate 'Newest first' %}</option>
|
||||
<option value="default" {% if order == 'default' %}selected{% endif %}>{% translate 'Default' %}</option>
|
||||
<option value="older" {% if order == 'older' %}selected{% endif %}>{% translate 'Oldest first' %}</option>
|
||||
<option value="newer" {% if order == 'newer' %}selected{% endif %}>{% translate 'Newest first' %}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,13 +3,13 @@ volumes:
|
||||
wygiwyh_temp:
|
||||
|
||||
services:
|
||||
web: &django
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./docker/dev/django/Dockerfile
|
||||
image: wygiwyh_dev_server
|
||||
container_name: wygiwyh_dev_server
|
||||
command: /start
|
||||
command: /start-supervisor
|
||||
volumes:
|
||||
- ./app/:/usr/src/app/:z
|
||||
- ./frontend/:/usr/src/frontend:z
|
||||
@@ -54,12 +54,12 @@ services:
|
||||
- '${SQL_PORT}:5432'
|
||||
restart: unless-stopped
|
||||
|
||||
procrastinate:
|
||||
<<: *django
|
||||
image: wygiwyh_dev_procrastinate
|
||||
container_name: wygiwyh_dev_procrastinate
|
||||
depends_on:
|
||||
- db
|
||||
ports: [ ]
|
||||
command: /start-procrastinate
|
||||
restart: unless-stopped
|
||||
# procrastinate:
|
||||
# <<: *django
|
||||
# image: wygiwyh_dev_procrastinate
|
||||
# container_name: wygiwyh_dev_procrastinate
|
||||
# depends_on:
|
||||
# - db
|
||||
# ports: [ ]
|
||||
# command: /start-procrastinate
|
||||
# restart: unless-stopped
|
||||
|
||||
@@ -2,15 +2,13 @@ services:
|
||||
web:
|
||||
image: eitchtee/wygiwyh:latest
|
||||
container_name: ${SERVER_NAME}
|
||||
command: /start
|
||||
command: /start-single
|
||||
ports:
|
||||
- "${OUTBOUND_PORT}:8000"
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
- db
|
||||
volumes:
|
||||
- wygiwyh_temp:/usr/src/app/temp/
|
||||
restart: unless-stopped
|
||||
|
||||
db:
|
||||
@@ -23,18 +21,3 @@ services:
|
||||
- POSTGRES_USER=${SQL_USER}
|
||||
- POSTGRES_PASSWORD=${SQL_PASSWORD}
|
||||
- POSTGRES_DB=${SQL_DATABASE}
|
||||
|
||||
procrastinate:
|
||||
image: eitchtee/wygiwyh:latest
|
||||
container_name: ${PROCRASTINATE_NAME}
|
||||
depends_on:
|
||||
- db
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- wygiwyh_temp:/usr/src/app/temp/
|
||||
command: /start-procrastinate
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
wygiwyh_temp:
|
||||
|
||||
@@ -18,7 +18,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
COPY --from=python-build-stage /usr/src/app/wheels /wheels/
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -y gettext && \
|
||||
apt-get install --no-install-recommends -y gettext supervisor && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
pip install --upgrade pip && \
|
||||
pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* && \
|
||||
@@ -26,9 +26,15 @@ RUN apt-get update && \
|
||||
|
||||
COPY ./docker/dev/django/start /start
|
||||
COPY ./docker/dev/procrastinate/start /start-procrastinate
|
||||
COPY ./docker/dev/supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY ./docker/dev/supervisord/supervisord.conf /etc/supervisord.conf
|
||||
COPY ./docker/dev/supervisord/start /start-supervisor
|
||||
|
||||
RUN sed -i 's/\r$//g' /start && \
|
||||
chmod +x /start && \
|
||||
sed -i 's/\r$//g' /start-procrastinate && \
|
||||
chmod +x /start-procrastinate
|
||||
chmod +x /start-procrastinate && \
|
||||
sed -i 's/\r$//g' /start-supervisor && \
|
||||
chmod +x /start-supervisor
|
||||
|
||||
COPY ./app .
|
||||
|
||||
9
docker/dev/supervisord/start
Normal file
9
docker/dev/supervisord/start
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
set -o nounset
|
||||
|
||||
export TASK_WORKERS=${TASK_WORKERS:=1}
|
||||
|
||||
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
39
docker/dev/supervisord/supervisord.conf
Normal file
39
docker/dev/supervisord/supervisord.conf
Normal file
@@ -0,0 +1,39 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/tmp/supervisord.pid
|
||||
user=root
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///run/supervisord.sock
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[unix_http_server]
|
||||
file=/run/supervisord.sock
|
||||
chmod=0700
|
||||
|
||||
[program:web]
|
||||
directory=/usr/src/app
|
||||
command=/bin/bash /start
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startretries=5
|
||||
|
||||
[program:procrastinate]
|
||||
directory=/usr/src/app
|
||||
command=/bin/bash /start-procrastinate
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
numprocs=%(ENV_TASK_WORKERS)s
|
||||
numprocs_start=1
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startretries=5
|
||||
@@ -31,7 +31,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
COPY --from=python-build-stage /usr/src/app/wheels /wheels/
|
||||
RUN --mount=type=cache,target=/root/.cache/apt \
|
||||
apt-get update && \
|
||||
apt-get install --no-install-recommends -y gettext && \
|
||||
apt-get install --no-install-recommends -y gettext supervisor && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
pip install --upgrade pip && \
|
||||
pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* && \
|
||||
@@ -39,10 +39,15 @@ RUN --mount=type=cache,target=/root/.cache/apt \
|
||||
|
||||
COPY --chown=app:app ./docker/prod/django/start /start
|
||||
COPY --chown=app:app ./docker/prod/procrastinate/start /start-procrastinate
|
||||
COPY --chown=app:app ./docker/prod/supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY --chown=app:app ./docker/prod/supervisord/supervisord.conf /etc/supervisord.conf
|
||||
COPY --chown=app:app ./docker/prod/supervisord/start /start-single
|
||||
RUN sed -i 's/\r$//g' /start && \
|
||||
chmod +x /start && \
|
||||
sed -i 's/\r$//g' /start-procrastinate && \
|
||||
chmod +x /start-procrastinate
|
||||
chmod +x /start-procrastinate && \
|
||||
sed -i 's/\r$//g' /start-single && \
|
||||
chmod +x /start-single
|
||||
|
||||
COPY --chown=app:app ./app .
|
||||
|
||||
|
||||
9
docker/prod/supervisord/start
Normal file
9
docker/prod/supervisord/start
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
set -o nounset
|
||||
|
||||
export TASK_WORKERS=${TASK_WORKERS:=1}
|
||||
|
||||
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
37
docker/prod/supervisord/supervisord.conf
Normal file
37
docker/prod/supervisord/supervisord.conf
Normal file
@@ -0,0 +1,37 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/tmp/supervisord.pid
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/supervisord.sock
|
||||
|
||||
[unix_http_server]
|
||||
file=/tmp/supervisord.sock
|
||||
chmod=0700
|
||||
|
||||
[program:web]
|
||||
user=app
|
||||
directory=/usr/src/app
|
||||
command=/bin/bash /start
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startretries=5
|
||||
|
||||
[program:procrastinate]
|
||||
user=app
|
||||
directory=/usr/src/app
|
||||
command=/bin/bash /start-procrastinate
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
numprocs=%(ENV_TASK_WORKERS)s
|
||||
numprocs_start=1
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startretries=5
|
||||
Reference in New Issue
Block a user