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