Google App Engine Python - Protorpc && Taskqueue

Как использовать Task Queue (Push Queue) с Protorpc.

У меня есть форма целевой страницы, которая выполняет несколько действий при отправке:

  • Сохраните поля в хранилище данных
  • Отправить письмо отправителю формы
  • Отправьте поля в стороннее приложение (скажем, CRM)

Форма отправки реализована на стороне сервера с protorpc.

class FormRequest(messages.Message)
  field1 = messages.StringField(1, required=True)
  field2 = messages.StringField(2, required=True)

...

class FormApi(remote.Service):
  @remote.method(TravelRequest, message_types.VoidMessage)
  def insert(self, request):
    # Save the form in the DataStore
    travel = FormModel(field1=request.field1, field2=request.field2)
    travel.put()

    # Send an email to the client
    ...

    # Send the data to a third party
    ...

    return message_types.VoidMessage()

Это решение застряло, потому что пользователь должен ждать все это время запроса. (В данном случае это всего 2-3 секунды, но это много для формы целевой страницы)

Хорошим решением будет использование taskqueue, чтобы минимизировать время ожидания пользователя:

(В качестве примера)

class ...
  @remote ...
  def ...
    # Save the form in the DataStore
    taskqueue.add(url='/api/worker/save_to_db', params={'field1': request.field1, 'field2': request.field2})
    # Send an email to the client
    taskqueue.add(url='/api/worker/send_email', params={'field1': request.field1, 'field2': request.field2})
    # Send the data to a third party (CRM)
    taskqueue.add(url='/api/worker/send_to_crm', params={'field1': request.field1, 'field2': request.field2})

"Проблема" в том, что protorpc получает в качестве запроса только объект json. Как это сделать с помощью TaskQueue(Push)?

Поведение TaskQueue по умолчанию - отправка параметров в виде строки urlencoded, и это не удобно для protorpc.

2 ответа

Решение

Давайте определим сервис Worker для очереди задач:

class WorkersApi(remote.Service):
  @remote.method(TravelRequest, message_types.VoidMessage)
  def save_to_db(self, request):
    # Instead of write each parameter, I am using this "cheat"
    params = {}
    for field in request.all_fields():
      params[field.name] = getattr(request, field.name)

    # Save data in the datastore
    form_model = FormModel(**params)
    form_model.put()

    return message_types.VoidMessage()

Обратите внимание, что я использую то же самое message объект для реального запроса и для запроса очереди задач (это большое преимущество, не нужно создавать и разные message объект для каждого запроса) Вопрос в том, как использовать taskqueue с этой функцией protorpc.

Как я уже сказал в этом вопросе, стандартное поведение taskqueue не является удобным.

Решение состоит в том, чтобы преобразовать исходный объект запроса / сообщения (в нашем примере это FormRequest) обратно в строку и установить заголовок в taskqueue, что полезная нагрузка application/json ,

Вот код:

# This format string is take from the util file in the protorpc folder in Google App Engine source code
format_string = '%Y-%m-%dT%H:%M:%S.%f'

params = {}
for field in request.all_fields():
  value = getattr(request, field.name)
  if (isinstance(value, datetime.datetime)):
    value = value.strftime(format_string)
  params[field.name] = value

taskqueue.add(url='/api/workers.save_to_db', payload=json.dumps(params), headers={'content-type':'application/json'})

Сделайте то же самое для "электронной почты" и "crm".

Вы можете использовать put_async() для записи без времени: асинхронная запись данных объекта в хранилище данных.

например:

travel = FormModel(field1=request.field1, field2=request.field2)
travel.put_async()
# next action
Другие вопросы по тегам