From e8c2d4da10d7e1fe8952d0e61e2d0b2e5c87f72f Mon Sep 17 00:00:00 2001 From: Nigel Date: Thu, 14 Oct 2021 17:03:37 -0600 Subject: [PATCH 1/5] Add support for using redis as a cache and a broker --- InvenTree/InvenTree/settings.py | 103 +++++++++++++++++++++++--------- docker/requirements.txt | 3 + 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 944736e61d..2a0227400e 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -15,6 +15,7 @@ import logging import os import random +import socket import string import shutil import sys @@ -361,30 +362,6 @@ REST_FRAMEWORK = { WSGI_APPLICATION = 'InvenTree.wsgi.application' -background_workers = os.environ.get('INVENTREE_BACKGROUND_WORKERS', None) - -if background_workers is not None: - try: - background_workers = int(background_workers) - except ValueError: - background_workers = None - -if background_workers is None: - # Sensible default? - background_workers = 4 - -# django-q configuration -Q_CLUSTER = { - 'name': 'InvenTree', - 'workers': background_workers, - 'timeout': 90, - 'retry': 120, - 'queue_limit': 50, - 'bulk': 10, - 'orm': 'default', - 'sync': False, -} - """ Configure the database backend based on the user-specified values. @@ -562,12 +539,82 @@ DATABASES = { } -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - }, +_cache_config = CONFIG.get("cache", {}) +_cache_host = _cache_config.get("host", os.getenv("INVENTREE_CACHE_HOST")) +_cache_port = _cache_config.get("port", os.getenv("INVENTREE_CACHE_PORT")) + +if _cache_host: + # We are going to rely upon a possibly non-localhost for our cache, + # so don't wait too long for the cache as nothing in the cache should be + # irreplacable. Django Q Cluster will just try again later. + _cache_options = { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + "SOCKET_CONNECT_TIMEOUT": int(os.getenv("CACHE_CONNECT_TIMEOUT", "2")), + "SOCKET_TIMEOUT": int(os.getenv("CACHE_SOCKET_TIMEOUT", "2")), + "CONNECTION_POOL_KWARGS": { + "socket_keepalive": _is_true( + os.getenv("CACHE_TCP_KEEPALIVE", "1") + ), + "socket_keepalive_options": { + socket.TCP_KEEPCNT: int( + os.getenv("CACHE_KEEPALIVES_COUNT", "5") + ), + socket.TCP_KEEPIDLE: int( + os.getenv("CACHE_KEEPALIVES_IDLE", "1") + ), + socket.TCP_KEEPINTVL: int( + os.getenv("CACHE_KEEPALIVES_INTERVAL", "1") + ), + socket.TCP_USER_TIMEOUT: int( + os.getenv("CACHE_TCP_USER_TIMEOUT", "1000") + ), + }, + }, + } + CACHES = { + # Connection configuration for Django Q Cluster + "worker": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": f"redis://{_cache_host}:{_cache_port}/0", + "OPTIONS": _cache_options, + }, + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": f"redis://{_cache_host}:{_cache_port}/1", + "OPTIONS": _cache_options, + }, + } +else: + CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + }, + } + +try: + # 4 background workers seems like a sensible default + background_workers = int(os.environ.get('INVENTREE_BACKGROUND_WORKERS', 4)) +except ValueError: + background_workers = 4 + +# django-q configuration +Q_CLUSTER = { + 'name': 'InvenTree', + 'workers': background_workers, + 'timeout': 90, + 'retry': 120, + 'queue_limit': 50, + 'bulk': 10, + 'orm': 'default', + 'sync': False, } +if _cache_host: + # If using external redis cache, make the cache the broker for Django Q + # as well + Q_CLUSTER["django_redis"] = "worker" + + # Password validation # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators diff --git a/docker/requirements.txt b/docker/requirements.txt index b15d7c538d..1a110d6cde 100644 --- a/docker/requirements.txt +++ b/docker/requirements.txt @@ -11,3 +11,6 @@ psycopg2>=2.9.1 mysqlclient>=2.0.3 pgcli>=3.1.0 mariadb>=1.0.7 + +# Cache +django-redis>=5.0.0 From eecd477a341b08aa6b83729110607d7fc85a582f Mon Sep 17 00:00:00 2001 From: Nigel Date: Tue, 2 Nov 2021 16:07:29 -0600 Subject: [PATCH 2/5] Add redis cache to postgres testcase --- .github/workflows/postgresql.yaml | 6 ++++++ InvenTree/InvenTree/settings.py | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/postgresql.yaml b/.github/workflows/postgresql.yaml index 9a56382c4e..d3354f3a37 100644 --- a/.github/workflows/postgresql.yaml +++ b/.github/workflows/postgresql.yaml @@ -27,6 +27,7 @@ jobs: INVENTREE_DEBUG: info INVENTREE_MEDIA_ROOT: ./media INVENTREE_STATIC_ROOT: ./static + INVENTREE_CACHE_HOST: localhost services: postgres: @@ -37,6 +38,11 @@ jobs: ports: - 5432:5432 + redis: + image: redis + ports: + - 6379:6379 + steps: - name: Checkout Code uses: actions/checkout@v2 diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 2a0227400e..b425a1c41e 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -541,7 +541,9 @@ DATABASES = { _cache_config = CONFIG.get("cache", {}) _cache_host = _cache_config.get("host", os.getenv("INVENTREE_CACHE_HOST")) -_cache_port = _cache_config.get("port", os.getenv("INVENTREE_CACHE_PORT")) +_cache_port = _cache_config.get( + "port", os.getenv("INVENTREE_CACHE_PORT", "6379") +) if _cache_host: # We are going to rely upon a possibly non-localhost for our cache, From 58bb2b0c1b2803d8111de1ddb0722c1b17987360 Mon Sep 17 00:00:00 2001 From: Nigel Date: Tue, 2 Nov 2021 16:40:39 -0600 Subject: [PATCH 3/5] Add django redis to postgres dep installation --- .github/workflows/postgresql.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/postgresql.yaml b/.github/workflows/postgresql.yaml index d3354f3a37..b235767110 100644 --- a/.github/workflows/postgresql.yaml +++ b/.github/workflows/postgresql.yaml @@ -55,6 +55,7 @@ jobs: sudo apt-get install libpq-dev pip3 install invoke pip3 install psycopg2 + pip3 install django-redis>=5.0.0 invoke install - name: Run Tests run: invoke test From bae28e82079792d31d110ac20d6b3b3f0f7e4d91 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 10 Nov 2021 23:54:54 +0100 Subject: [PATCH 4/5] Add setting for enabeling reports Fixes #2278 --- InvenTree/build/templates/build/build_base.html | 4 ++++ InvenTree/build/templates/build/index.html | 4 ++++ InvenTree/common/models.py | 7 +++++++ InvenTree/order/templates/order/order_base.html | 4 ++++ InvenTree/order/templates/order/purchase_orders.html | 5 ++++- InvenTree/order/templates/order/sales_order_base.html | 4 ++++ InvenTree/order/templates/order/sales_orders.html | 5 ++++- InvenTree/part/templates/part/category.html | 2 ++ InvenTree/part/templates/part/detail.html | 4 ++++ InvenTree/templates/InvenTree/settings/report.html | 1 + InvenTree/templates/base.html | 1 + 11 files changed, 39 insertions(+), 2 deletions(-) diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index 826baf13ea..22a126fcdf 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -34,6 +34,7 @@ src="{% static 'img/blank_image.png' %}" {% include "admin_button.html" with url=url %} {% endif %} +{% if report_enabled %}
+{% endif %} {% if roles.build.change %}
@@ -224,9 +226,11 @@ src="{% static 'img/blank_image.png' %}" {% endif %} }); + {% if report_enabled %} $('#print-build-report').click(function() { printBuildReports([{{ build.pk }}]); }); + {% endif %} $("#build-delete").on('click', function() { launchModalForm( diff --git a/InvenTree/build/templates/build/index.html b/InvenTree/build/templates/build/index.html index ba8997ca05..b2c237c149 100644 --- a/InvenTree/build/templates/build/index.html +++ b/InvenTree/build/templates/build/index.html @@ -27,6 +27,7 @@
+ {% if report_enabled %}
+ {% endif %}
@@ -169,9 +171,11 @@ $("#place-order").click(function() { }); {% endif %} +{% if report_enabled %} $('#print-order-report').click(function() { printPurchaseOrderReports([{{ order.pk }}]); }); +{% endif %} $("#edit-order").click(function() { diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html index e15e009927..8ddae982b9 100644 --- a/InvenTree/order/templates/order/purchase_orders.html +++ b/InvenTree/order/templates/order/purchase_orders.html @@ -26,10 +26,11 @@
- + {% if report_enabled %} + {% endif %} @@ -169,6 +170,7 @@ $("#view-list").click(function() { $("#view-calendar").show(); }); +{% if report_enabled %} $("#order-print").click(function() { var rows = $("#purchase-order-table").bootstrapTable('getSelections'); @@ -180,6 +182,7 @@ $("#order-print").click(function() { printPurchaseOrderReports(orders); }) +{% endif %} $("#po-create").click(function() { createPurchaseOrder(); diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 0f705212db..368c3a2e47 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -39,7 +39,9 @@ src="{% static 'img/blank_image.png' %}"