You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tinkerpop.apache.org by "selfish finch (JIRA)" <ji...@apache.org> on 2019/08/06 14:33:00 UTC
[jira] [Created] (TINKERPOP-2277) Python sdk postpone the timing to
create transport
selfish finch created TINKERPOP-2277:
----------------------------------------
Summary: Python sdk postpone the timing to create transport
Key: TINKERPOP-2277
URL: https://issues.apache.org/jira/browse/TINKERPOP-2277
Project: TinkerPop
Issue Type: Improvement
Components: python
Affects Versions: 3.4.2
Reporter: selfish finch
The current timing of transport creation is inside connection.__init__. It's OK in all scenarios in one process model.
But if users need to run Gremlin Python SDK inside services like `celery` which use multiple processes model, this implementation may cause error.
As transport(which represents socket) is created inside Main Processes, it will be inherited by Child Processes, then threads inside ThreadPoolExecutor will try to read from the same socket, so it may happen that:
* Child Process 1 send a request with request id 'xxx' use socket s1
* Child Process 2 send another request with request id 'yyy' also use socket s1, then able to read the response of request id 'xxx', but unable to find 'xxx' inside '_results'
If this happens, it will cause KeyError exception like:
{code:java}
[2019-08-06 15:31:21,822: WARNING/ForkPoolWorker-3] Traceback (most recent call last):
File "/root/celery_gremlin/gremlin_test/tasks.py", line 15, in graph_query_test
res = client.submit(dsl).one()
File "/usr/local/lib/python3.6/site-packages/gremlin_python/driver/resultset.py", line 83, in one
return self.done.result()
File "/usr/lib64/python3.6/concurrent/futures/_base.py", line 425, in result
return self.__get_result()
File "/usr/lib64/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/usr/lib64/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.6/site-packages/gremlin_python/driver/connection.py", line 80, in _receive
status_code = self._protocol.data_received(data, self._results)
File "/usr/local/lib/python3.6/site-packages/gremlin_python/driver/protocol.py", line 83, in data_received
result_set = results_dict[request_id]
KeyError: '1ff0ad4a-dcea-45d1-b240-27c2dc792f73'
{code}
Steps to reproduce:
# Following the [tutorial|[https://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html]] of Celery to create a simple app named `tasks`
# Refactor `tasks.py` to send request through Gremin Python SDK inside the task method
{code:java}
from celery import Celery
from gremlin_python.driver import client
username = "test"
password = "test"
my_client = client.Client('ws://localhost:8182/gremlin', 'g',
username=username, password=password,
pool_size=1, max_workers=1)
app = Celery('tasks', broker='redis://localhost', backend='redis://localhost:6379/0')
@app.task
def add(x, y):
dsl = "g.V().count()"
my_client.submit(dsl).one()
return x + y
{code}
# Invoke `add.delay(1,2)`
There is a quick fix which changes several lines inside `connection.py` without breaking other code:
{code:java}
class Connection:
def __init__(self, url, traversal_source, protocol, transport_factory,
executor, pool):
self._url = url
self._traversal_source = traversal_source
self._protocol = protocol
self._transport_factory = transport_factory
self._executor = executor
self._transport = None
self._pool = pool
self._results = {}
self._inited = False
def connect(self):
if self._transport:
self._transport.close()
self._transport = self._transport_factory()
self._transport.connect(self._url)
self._protocol.connection_made(self._transport)
self._inited = True
def close(self):
if self._inited:
self._transport.close()
def write(self, request_message):
if not self._inited:
self.connect()
{code}
--
This message was sent by Atlassian JIRA
(v7.6.14#76016)