我机智。我研究了一段时间,也许我不知道正确的关键字,但找不到有效的解决方案。
我已经用Postgres后端对Django应用程序(自定义链接缩短程序)进行了docker化,该后端使用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"?
以下是我认为相关的代码,但是如果我未包含某些内容,请告诉我。谢谢。
docker-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)
来自app 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"