Я в конце. Некоторое время я проводил исследования, и, возможно, я не знаю правильных ключевых слов, но я не смог найти решение, которое сработало.
Я докернизировал приложение Django (пользовательское средство сокращения ссылок) с бэкэндом Postgres, который использует Celery, RabbitMQ для одной задачи - для создания и сохранения объекта в базе данных при выполнении запроса GET.
Идея такова: когда запрашивается короткая ссылка (запрос GET), приложение просто перенаправляет запрос на другой URL, но также создает задачу с помощью Celery. Эта задача должна добавить аналитическую запись в базу данных Postgres. Перенаправление работает отлично. Я могу создавать новые короткие ссылки просто отлично. Приложение django нормально подключается к контейнеру postgres. Но Celery в другом контейнере пытается соединиться при создании и сохранении нового объекта в контейнере postgres через сокет. Это основная ошибка:
celery | django.db.utils.OperationalError: could not connect to server: No such file or directory
celery | Is the server running locally and accepting
celery | connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
Ниже приведен код, который я считаю соответствующим, но если я что-то не включил, пожалуйста, дайте мне знать. Спасибо.
докер-compose.yml:
version: '3.6'
services:
pgdb:
container_name: postgres
restart: unless-stopped
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
image: postgres:10-alpine
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgres/data
networks:
- net1
rabbitmq:
container_name: rabbitmq
restart: always
image: rabbitmq:3.7-alpine
environment:
- RABBITMQ_DEFAULT_USER=slinky
- RABBITMQ_DEFAULT_PASS=pwd
depends_on:
- pgdb
networks:
- net1
ports:
- 5672:5672
django:
container_name: django
restart: unless-stopped
environment:
- DB_NAME=postgres
- DB_USER=postgres
- DB_PASSWORD=password
- DB_HOST=pgdb
- DB_PORT=5432
build:
context: .
dockerfile: docker/django.dockerfile
command: sh -c "/usr/local/bin/gunicorn slinky.wsgi -w 2 -b 0.0.0.0:8000 --log-file gunicorn.log"
volumes:
- .:/code
- /tmp
networks:
- net1
ports:
- 8000:8000
depends_on:
- pgdb
- rabbitmq
celery:
container_name: celery
restart: unless-stopped
build:
context: .
dockerfile: docker/django.dockerfile
command: celery -A slinky worker -l info
volumes:
- .:/code
depends_on:
- rabbitmq
networks:
- net1
nginx:
container_name: nginx
restart: unless-stopped
build:
context: .
dockerfile: docker/nginx.dockerfile
volumes:
- .:/code
ports:
- 80:80
networks:
- net1
depends_on:
- django
volumes:
postgres_data:
networks:
net1:
driver: bridge
name: net1
tasks.py:
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from django.conf import settings
from django.db import models
from .utils import ip2country
@shared_task
def redirect_event(url, slink, label, ip):
country = "Switzerland" # ip2country(ip)
print("Saving redirect event object: ", country)
obj = RedirectEvent(url=url, slink=slink, label=label, country=country)
obj.save()
utils.py:
from django.conf import settings
from django.db import models
import random
import string
import requests
SLINK_LENGTH = getattr(settings, "SLINK_LENGTH", 6)
def code_gen(size=SLINK_LENGTH, chars = string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def create_code(instance, size=SLINK_LENGTH):
new_code = code_gen(size=size)
Klass = instance.__class__
qs_exists = Klass.objects.filter(shortcode=new_code).exists()
if qs_exists:
return create_code(size=size)
return new_code
def ip2country(ip):
url = "http://api.ipaddress.com/iptocountry?format=json&ip=" + ip
print("IP2 country API call: ", url)
r = requests.get(url)
data = r.json()
return data['country_name']
views.py:
from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views import View
from .models import Slink, SlinkBaseDomain, RedirectEvent
from shortener.tasks import redirect_event
SLINK_BASE = getattr(settings, "SLINK_BASE", "www.meydan.tv")
class SlinkRedirectView(View):
def get(self, request, slink=None, *args, **kwargs):
obj = get_object_or_404(Slink, shortcode=slink)
latest_domain_obj = SlinkBaseDomain.objects.latest()
latest_domain = latest_domain_obj.domain
url = latest_domain + obj.url
ip = request.META['REMOTE_ADDR']
# celery task (delayed job)
redirect_event.delay(obj.url, slink, obj.label, ip)
print("================= Redirecting user to external URL: ", url)
return HttpResponseRedirect(url)
из приложения models.py:
class RedirectEvent(models.Model):
url = models.CharField(max_length=255)
slink = models.CharField(max_length=SLINK_LENGTH)
country = models.CharField(max_length=255, blank=True)
label = models.CharField(max_length=25, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.slink)
class Meta:
verbose_name = "Redirect Analytic"