Каждое задание не выполняется в облачных задачах Google - PullRequest
2 голосов
/ 09 марта 2020

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

Проблема в том, что все созданные задачи go помещаются в очередь, но не выполняются. Консоль и логи сообщают только http-код 301 (постоянное перенаправление). Для простоты я развернул один и тот же код на двух сервисах App Engine (стандарт) и направил запрос на выполнение задач только одному из них.

Похоже, что сам код работает нормально. Когда я go в " https: // [proj] .appspot.com / api / v1 / tasks ", подпрограмма выполняется хорошо, и перенаправления в соответствии с DevTools / Network не происходит. Когда облачные задачи пытаются вызвать «/ api / v1 / tasks», каждый раз происходит сбой.

Если кто-нибудь может взглянуть на приведенный ниже код и указать, что может быть причиной этой ошибки, я был бы признателен очень много.

Спасибо.

#--------------------------------
# [proj]/.../urls.py
#--------------------------------
from [proj].api import tasks

urlpatterns += [
    # tasks api
    path('api/v1/tasks', tasks, name='tasks'),
]
#--------------------------------
#   [proj]/api.py:
#--------------------------------
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def tasks(request):
    print('Start api')
    payload = request.body.decode("utf-8")
    print (payload)
    print('End api')
    return HttpResponse('OK')

#--------------------------------
# [proj]/views/manut.py
#--------------------------------
from django.views.generic import View
from django.shortcuts import redirect
from [proj].tasks import TasksCreate

class ManutView(View):
    template_name = '[proj]/manut.html'

    def post(self, request, *args, **kwargs):
        relative_url = '/api/v1/tasks'
        testa_task = TasksCreate()
        resp = testa_task.send_task(
            url=relative_url,
            schedule_time=5,
            payload={'task_type': 1, 'id': 21}
        )
        print(resp)
        return redirect(request.META['HTTP_REFERER'])

#--------------------------------
# [proj]/tasks/tasks.py:
#--------------------------------
from django.conf import settings
from google.cloud import tasks_v2
from google.protobuf import timestamp_pb2
from typing import Dict, Optional, Union
import json
import time

class TasksCreate:

    def send_task(self,
        url: str,
        payload: Optional[Union[str, Dict]] = None,
        schedule_time: Optional[int] = None,    # in seconds
        name: Optional[str] = None,
        ) -> None:

        client = tasks_v2.CloudTasksClient()
        parent = client.queue_path(
            settings.GCP_PROJECT,
            settings.GCP_LOCATION,
            settings.GCP_QUEUE,
        )

        # App Engine task:
        task = {
            'app_engine_http_request': {  # Specify the type of request.
                'http_method': 'POST',
                'relative_uri': url,
                'app_engine_routing': {'service': 'tasks'}
            }
        }

        if name:
            task['name'] = name
        if isinstance(payload, dict):
            payload = json.dumps(payload)
        if payload is not None:
            converted_payload = payload.encode()
            # task['http_request']['body'] = converted_payload
            task['app_engine_http_request']['body'] = converted_payload
        if schedule_time is not None:
            now = time.time() + schedule_time
            seconds = int(now)
            nanos = int((now - seconds) * 10 ** 9)
            # Create Timestamp protobuf.
            timestamp = timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)
            # Add the timestamp to the tasks.
            task['schedule_time'] = timestamp

        resp = client.create_task(parent, task)

        return resp

# --------------------------------
# [proj]/dispatch.yaml:
# --------------------------------
dispatch:
  - url: "*/api/v1/tasks"
    service: tasks

  - url: "*/api/v1/tasks/"
    service: tasks

  - url: "*appspot.com/*"
    service: default

#--------------------------------
# [proj]/app.yaml & tasks.yaml:
#--------------------------------
runtime: python37

instance_class: F1

automatic_scaling:
  max_instances: 2

service: default

#handlers:
#- url: .*
#  secure: always
#  redirect_http_response_code: 301
#  script: auto

entrypoint: gunicorn -b :$PORT --chdir src server.wsgi

env_variables:
...

ОБНОВЛЕНИЕ:

Вот журналы для исполнение:

{
 insertId: "1lfs38fa9"  
 jsonPayload: {
  @type: "type.googleapis.com/google.cloud.tasks.logging.v1.TaskActivityLog"   
  attemptResponseLog: {
   attemptDuration: "0.008005s"    
   dispatchCount: "5"    
   maxAttempts: 0    
   responseCount: "5"    
   retryTime: "2020-03-09T21:50:33.557783Z"    
   scheduleTime: "2020-03-09T21:50:23.548409Z"    
   status: "UNAVAILABLE"    
   targetAddress: "POST /api/v1/tasks"    
   targetType: "APP_ENGINE_HTTP"    
  }
  task: "projects/[proj]/locations/us-central1/queues/tectaq/tasks/09687434589619534431"   
 }
 logName: "projects/[proj]/logs/cloudtasks.googleapis.com%2Ftask_operations_log"  
 receiveTimestamp: "2020-03-09T21:50:24.375681687Z"  
 resource: {
  labels: {
   project_id: "[proj]"    
   queue_id: "tectaq"    
   target_type: "APP_ENGINE_HTTP"    
  }
  type: "cloud_tasks_queue"   
 }
 severity: "ERROR"  
 timestamp: "2020-03-09T21:50:23.557842532Z"  
}

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Наконец я смог заставить работать облачные задачи, но только используя тип http_request (с абсолютным URL). Не было никакого способа заставить задачи выполняться, когда они были определены как app_engine_http_request (относительный URL).

Я уже пробовал тип http_request с POST, но это было до того, как я освободил функцию api от csrf токен был проверен ранее, и это вызвало ошибку Forbidden (Referer checking failed - no Referer.): /api/v1/tasks, которую я не смог подключить к пропуску csrf.

Если кто-нибудь наткнется на эту проблему в будущем и найдет способ заставить app_engine_http_request работать над Облачные задачи с Django, мне бы очень хотелось узнать решение.

0 голосов
/ 11 марта 2020

Проблема в том, что все созданные задачи go помещаются в очередь, но не выполняются. Консоль и журналы сообщают только http-код 301 (постоянное перенаправление).

Возможно, обработчик запросов для вашей конечной точки задачи хочет получить конечный sla sh.

Попробуйте изменить это :

class ManutView(View):
    template_name = '[proj]/manut.html'

    def post(self, request, *args, **kwargs):
        relative_url = '/api/v1/tasks'
        ...

на это:

class ManutView(View):
    template_name = '[proj]/manut.html'

    def post(self, request, *args, **kwargs):
        relative_url = '/api/v1/tasks/'
        ...

Также просто попробуйте нажать URL-адрес задачи самостоятельно и посмотреть, сможете ли вы запустить задачу из curl

...