mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-02-25 00:44:52 +01:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd7ecd42ea | ||
|
|
0b83ad6b3e | ||
|
|
d0ef08252e | ||
|
|
1140d9c896 | ||
|
|
b2843a1ec1 | ||
|
|
d25aba7be9 | ||
|
|
c3eaca3e9a | ||
|
|
5677706452 | ||
|
|
5bf7f9f272 | ||
|
|
448841dadc | ||
|
|
1b6934694e | ||
|
|
d4d00ba02f | ||
|
|
19a65ac45f | ||
|
|
b72e7bd707 | ||
|
|
190be3e813 | ||
|
|
88300b314c | ||
|
|
fab77c8d9f | ||
|
|
1ae7158d7e | ||
|
|
05f0356288 | ||
|
|
b3cea17b8d | ||
|
|
0b66b23f16 | ||
|
|
80fdf70f7d | ||
|
|
fa931b0db2 | ||
|
|
cab79b4203 | ||
|
|
ddab3db6b5 | ||
|
|
9fa704811c | ||
|
|
4c0d14def0 | ||
|
|
43382d2ffe | ||
|
|
65ad51c273 |
@@ -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,
|
||||
)
|
||||
|
||||
52
app/apps/common/templatetags/markdown.py
Normal file
52
app/apps/common/templatetags/markdown.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from typing import Optional
|
||||
|
||||
import mistune
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
from mistune import HTMLRenderer, Markdown, BlockParser, InlineParser, safe_entity
|
||||
from mistune.plugins.formatting import strikethrough as plugin_strikethrough
|
||||
from mistune.plugins.url import url as plugin_url
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
class CustomRenderer(HTMLRenderer):
|
||||
def link(self, text: str, url: str, title: Optional[str] = None) -> str:
|
||||
s = '<a rel="nofollow" target="_blank" href="' + self.safe_url(url) + '"'
|
||||
if title:
|
||||
s += ' title="' + safe_entity(title) + '"'
|
||||
return s + ">" + text + "</a>"
|
||||
|
||||
def paragraph(self, text: str) -> str:
|
||||
return text + "\n"
|
||||
|
||||
def softbreak(self) -> str:
|
||||
return "\n"
|
||||
|
||||
def blank_line(self) -> str:
|
||||
return "\n"
|
||||
|
||||
|
||||
block = BlockParser()
|
||||
block.rules = ["blank_line"]
|
||||
inline = InlineParser(hard_wrap=False)
|
||||
inline.rules = [
|
||||
"emphasis",
|
||||
"link",
|
||||
"auto_link",
|
||||
"auto_email",
|
||||
"linebreak",
|
||||
"softbreak",
|
||||
]
|
||||
markdown = Markdown(
|
||||
renderer=CustomRenderer(escape=False),
|
||||
block=block,
|
||||
inline=inline,
|
||||
plugins=[plugin_strikethrough, plugin_url],
|
||||
)
|
||||
|
||||
|
||||
@register.filter(name="limited_markdown")
|
||||
def limited_markdown(value):
|
||||
return mark_safe(markdown(value))
|
||||
@@ -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.get("monthly_transactions_order", "default"):
|
||||
request.session["monthly_transactions_order"] = order
|
||||
|
||||
f = TransactionsFilter(request.GET)
|
||||
transactions_filtered = (
|
||||
@@ -76,9 +84,12 @@ def transactions_list(request, month: int, year: int):
|
||||
"account__group",
|
||||
"category",
|
||||
"tags",
|
||||
"tags__id",
|
||||
"account__exchange_currency",
|
||||
"account__currency",
|
||||
"installment_plan",
|
||||
"entities__name",
|
||||
"entities__id",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -313,24 +313,35 @@ 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.get("all_transactions_order", "default"):
|
||||
request.session["all_transactions_order"] = order
|
||||
|
||||
transactions = Transaction.objects.prefetch_related(
|
||||
"account",
|
||||
"account__group",
|
||||
"category",
|
||||
"tags",
|
||||
"tags__id",
|
||||
"account__exchange_currency",
|
||||
"account__currency",
|
||||
"installment_plan",
|
||||
"entities__name",
|
||||
"entities__id",
|
||||
).all()
|
||||
|
||||
transactions = default_order(transactions, order=order)
|
||||
|
||||
@@ -9,8 +9,8 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-28 00:49+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 13:27-0300\n"
|
||||
"Last-Translator: Herculino Trotta\n"
|
||||
"PO-Revision-Date: 2025-01-29 06:12+0100\n"
|
||||
"Last-Translator: Dimitri Decrock <dimitri@fam-decrock.eu>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -323,8 +323,6 @@ msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: apps/common/views.py:110
|
||||
#, fuzzy
|
||||
#| msgid "Category updated successfully"
|
||||
msgid "Cache cleared successfully"
|
||||
msgstr "Categorie succesvol bijgewerkt"
|
||||
|
||||
@@ -1180,7 +1178,7 @@ msgstr "Tijdsnotatie"
|
||||
|
||||
#: apps/users/forms.py:102 apps/users/models.py:48
|
||||
msgid "Number Format"
|
||||
msgstr "Nummerformat"
|
||||
msgstr "Schrijfwijze Nummers"
|
||||
|
||||
#: apps/users/forms.py:131
|
||||
msgid "Save"
|
||||
@@ -1906,8 +1904,6 @@ msgid "Settings"
|
||||
msgstr "Instellingen"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:38
|
||||
#, fuzzy
|
||||
#| msgid "Clear"
|
||||
msgid "Clear cache"
|
||||
msgstr "Leegmaken"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% load markdown %}
|
||||
{% load i18n %}
|
||||
<div class="transaction d-flex my-1 {% if transaction.type == "EX" %}expense{% else %}income{% endif %}">
|
||||
{% if not disable_selection %}
|
||||
@@ -54,7 +55,7 @@
|
||||
{% if transaction.notes %}
|
||||
<div class="row mb-2 mb-lg-1 tw-text-gray-400">
|
||||
<div class="col-auto pe-1"><i class="fa-solid fa-align-left fa-fw me-1 fa-xs"></i></div>
|
||||
<div class="col ps-0">{{ transaction.notes | linebreaksbr }}</div>
|
||||
<div class="col ps-0">{{ transaction.notes | limited_markdown | linebreaksbr }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# Category#}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -26,3 +26,4 @@ python-dateutil~=2.9.0.post0
|
||||
simpleeval~=1.0.0
|
||||
pydantic~=2.10.5
|
||||
PyYAML~=6.0.2
|
||||
mistune~=3.1.1
|
||||
|
||||
Reference in New Issue
Block a user