Включение моделей в функцию обратного вызова из библиотеки ctypes

Я пытаюсь настроить приложение на основе Google App Engine с помощью функции управляемой виртуальной машины.

Я использую общую библиотеку, написанную на C ++ с использованием ctypes

cdll.LoadLibrary('./mylib.so')

который регистрирует функцию обратного вызова

CB_FUNC_TYPE = CFUNCTYPE(None, eSubscriptionType)
cbFuncType = CB_FUNC_TYPE(scrptCallbackHandler)

в котором я хочу сохранить данные в хранилище данных ndb

def scrptCallbackHandler(arg):
    model = Model(name=str(arg.data))
    model.put()

Я регистрирую функцию обратного вызова, в которой я хочу взять данные из программы C ++ и поместить их в хранилище данных ndb. Это приводит к ошибке. На сервере разработки он ведет себя немного иначе, поэтому с производственного сервера:

suspended generator _put_tasklet(context.py:343) raised BadRequestError(Application Id (app) format is invalid: '_')LOG 2 1429698464071045 suspended generator put(context.py:810) raised BadRequestError(Application Id (app) format is invalid: '_') Traceback (most recent call last): File "_ctypes/callbacks.c", line 314, in 'calling callback function' File "/home/vmagent/app/isw_cloud_client.py", line 343, in scrptCallbackHandler node.put() File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/model.py", line 3380, in _put return self._put_async(**ctx_options).get_result() File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/tasklets.py", line 325, in get_result self.check_success() File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/tasklets.py", line 368, in _help_tasklet_along value = gen.throw(exc.__class__, exc, tb) File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/context.py", line 810, in put key = yield self._put_batcher.add(entity, options) File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/tasklets.py", line 368, in _help_tasklet_along value = gen.throw(exc.__class__, exc, tb) File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/context.py", line 343, in _put_tasklet keys = yield self._conn.async_put(options, datastore_entities) File "/home/vmagent/python_vm_runtime/google/appengine/ext/ndb/tasklets.py", line 454, in _on_rpc_completion result = rpc.get_result() File "/home/vmagent/python_vm_runtime/google/appengine/api/apiproxy_stub_map.py", line 613, in get_result return self.__get_result_hook(self) File "/home/vmagent/python_vm_runtime/google/appengine/datastore/datastore_rpc.py", line 1827, in __put_hook self.check_rpc_success(rpc) File "/home/vmagent/python_vm_runtime/google/appengine/datastore/datastore_rpc.py", line 1342, in check_rpc_success raise _ToDatastoreError(err)google.appengine.api.datastore_errors.BadRequestError: Application Id (app) format is invalid: '_'

Запуск программы C ++ запускается вызовом обработчика запросов, но выполняется в фоновом режиме и принимает входящие данные, которые должны быть обработаны в обратном вызове.

Обновление. Как уже указывал Тим, похоже, что контекст обработчика wsgi потерян. Скорее всего, решением здесь было бы как-то создать контекст приложения.


comment
Большая часть ответа находится в трассировке стека - «(Формат идентификатора приложения (app) недействителен:« _ »)» Когда создается ключ, одним из его элементов является идентификатор приложения. Я предполагаю, что в контексте обратного вызова среда, настроенная обработчиком wsgi, больше не присутствует. Зарегистрируйте env в своем обратном вызове и сравните его перед запуском кода ctypes. Посмотрите, можете ли вы поместить вещи в локальное хранилище потока, прежде чем вызывать ctypes, и посмотрите, можно ли это получить при обратном вызове. У меня такое чувство, что то, что вы пытаетесь сделать, не сработает из-за того, как работают библиотеки хранилища данных.   -  person Tim Hoffman    schedule 22.04.2015
comment
Я думаю, вы привели меня в правильное русло, в os.environ ничего нет, я думаю, что мне нужно как-то создать контекст.   -  person pfried    schedule 22.04.2015


Ответы (1)


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

Контекст выполнения функций обратного вызова несколько отличается от остальной части приложения Python. Любая асинхронная операция в обратном вызове завершается ошибкой. Я попытался выполнить http-вызов или сохранить его в хранилище данных. Операции никогда не завершаются, и после 60 секунд приложение показывает ошибку, что они разбились. Я предполагаю, что это связано с тем, как питон управляет выполнением и соответствующим распределением памяти.

Мне удалось выполнить обратный вызов в контексте объекта, заключив его в замыкание внутри класса. На самом деле это не было проблемой, но решение можно найти в следующем ответе: Как заставить методы работать как обратные вызовы с типами python?

Для своего решения я теперь использую комбинацию конечных точек облака в другом модуле и фоновых потоков в модуле ctypes.

В C-Callback я запускаю фоновый поток, который может выполнять асинхронную работу.

# Start a background thread using the background thread service from GAE
background_thread.start_new_background_thread(putData, [name, value])

И вот простая задача, которую он выполняет:

# Here i call my cloud-endpoints
def putData(name, value):
    body = {
        'name' : 'name',
        'value' : int(value)
    }
    res = service.objects().create(body=body).execute()

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

Примечание. Не удалось добавить модели в хранилище данных в потоке bg, поскольку среда в потоке bg отличается от приложения, а идентификатор приложения не был установлен.

person pfried    schedule 23.04.2015