Создание модели в проводах задач не может подключиться к базе данных postgres - пытается использовать сокет вместо сетевого порта - PullRequest
0 голосов
/ 02 сентября 2018

Я в конце. Некоторое время я проводил исследования, и, возможно, я не знаю правильных ключевых слов, но я не смог найти решение, которое сработало.

Я докернизировал приложение 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"
...