Title: Possible race condition between `_on_response` and `close` · Issue #997 · googleapis/python-pubsub · GitHub
Open Graph Title: Possible race condition between `_on_response` and `close` · Issue #997 · googleapis/python-pubsub
X Title: Possible race condition between `_on_response` and `close` · Issue #997 · googleapis/python-pubsub
Description: Environment details OS type and version: Ubuntu 22.04 Python version: 3.11 pip version: 23.0.1 google-cloud-pubsub version: 2.18.4 Steps to reproduce Run code sample indefinitely Sometime it shows Assertion error in _on_response function...
Open Graph Description: Environment details OS type and version: Ubuntu 22.04 Python version: 3.11 pip version: 23.0.1 google-cloud-pubsub version: 2.18.4 Steps to reproduce Run code sample indefinitely Sometime it shows ...
X Description: Environment details OS type and version: Ubuntu 22.04 Python version: 3.11 pip version: 23.0.1 google-cloud-pubsub version: 2.18.4 Steps to reproduce Run code sample indefinitely Sometime it shows ...
Opengraph URL: https://github.com/googleapis/python-pubsub/issues/997
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Possible race condition between `_on_response` and `close`","articleBody":"\r\n#### Environment details\r\n\r\n - OS type and version: Ubuntu 22.04\r\n - Python version: 3.11\r\n - pip version: 23.0.1\r\n - `google-cloud-pubsub` version: 2.18.4\r\n\r\n#### Steps to reproduce\r\n\r\n 1. Run code sample indefinitely\r\n 2. Sometime it shows Assertion error in `_on_response` function.\r\n\r\n#### Code example\r\n\r\n```python\r\ndef on_subscribe(subscription, until=None):\r\n \"\"\"Decorator factory that provides subscribed messages to function.\r\n It handle decorated function as callback. So message should be acked/nacked\r\n inside decorated function.\r\n\r\n Args:\r\n subscription (str): Subscription ID. \r\n Should be `projects/{PROJECT_ID}/subscriptions/{SUBSCRIPTION_ID}`\r\n until (datetime.datetime): This function will subscribe messages\r\n published until this timestamp.\r\n \"\"\"\r\n\r\n def _callback_factory(func, finished, subscribe_until, **kwargs):\r\n\r\n def _callback(message):\r\n \"\"\"Callback function.\r\n \r\n It sends signal if subscribed all messages.\r\n \"\"\"\r\n publish_time = datetime.fromtimestamp(\r\n message.publish_time.timestamp())\r\n if subscribe_until and publish_time \u003c= subscribe_until:\r\n return func(message, **kwargs)\r\n if subscribe_until and not finished.is_set():\r\n logging.info('Subscribed all messages published until %s',\r\n subscribe_until)\r\n finished.set()\r\n message.nack()\r\n\r\n return _callback\r\n\r\n def _wrapper(func):\r\n\r\n @functools.wraps(func)\r\n def _inner_wrapper(**kwargs):\r\n # Event variable that is triggered when all messages are subscribed\r\n all_subscribed = Event()\r\n\r\n callback = _callback_factory(func=func,\r\n finished=all_subscribed,\r\n subscribe_until=subscribe_until,\r\n **kwargs)\r\n\r\n # Ensure closing subscriber for memory leak prevention.\r\n with pubsub_v1.SubscriberClient() as subscriber:\r\n future = subscriber.subscribe(\r\n subscription=subscription,\r\n callback=callback,\r\n await_callbacks_on_shutdown=True,\r\n flow_control=pubsub_v1.types.FlowControl(max_messages=5000),\r\n )\r\n\r\n all_subscribed.wait(timeout=60)\r\n\r\n # Wait until future is finished when it's cancelled.\r\n # If it cancelled by timeout or keyboard interrupt, ignore it.\r\n try:\r\n future.cancel()\r\n future.result(timeout=60)\r\n except (KeyboardInterrupt, TimeoutError):\r\n pass\r\n except Exception as e:\r\n logging.error(\"Error occurs during subscription to %s: %s\",\r\n subscription, str(e))\r\n\r\n return _inner_wrapper\r\n\r\n return _wrapper\r\n\r\n@on_subscribe(subscription=\"SUBSCRIPTION\")\r\ndef callback(message):\r\n # Do something with message\r\n```\r\n\r\n#### Stack trace\r\n```\r\nTraceback (most recent call last):\r\n File \"/layers/google.python.pip/pip/lib/python3.11/site-packages/google/api_core/bidi.py\", line 657, in _thread_main\r\n self._on_response(response)\r\n File \"/layers/google.python.pip/pip/lib/python3.11/site-packages/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py\", line 1107, in _on_response\r\n assert self._scheduler is not None\r\n```\r\n\r\n#### Explanation\r\nIt's because `future.cancel()` executes `manager.close()` which makes `_scheduler` as `None` and it makes `_on_response` raise AssertionError.\r\n\r\nMaybe it has to be protected by threading lock somehow.","author":{"url":"https://github.com/hson2","@type":"Person","name":"hson2"},"datePublished":"2023-09-21T05:43:50.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/997/python-pubsub/issues/997"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:1f0dde86-2898-0cda-e740-454337cfb5a5 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E2E2:30372D:1470436:1DCF61B:6A4E481C |
| html-safe-nonce | c589a87f0d958560082e3b57e46694d54d3f861237c420327e618c68be8ad5af |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFMkUyOjMwMzcyRDoxNDcwNDM2OjFEQ0Y2MUI6NkE0RTQ4MUMiLCJ2aXNpdG9yX2lkIjoiNDU3NDQzNDY1MTAzMjk2NTQwIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 63c882ed718cbd44077d9e8a349e5705331e953c5645e580d07739580e573de5 |
| hovercard-subject-tag | issue:1906154179 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/googleapis/python-pubsub/997/issue_layout |
| twitter:image | https://opengraph.githubassets.com/434381c089e42902b5400ef3abd9900fc99f6e1cbc9ca1ef1481a3ae64f03786/googleapis/python-pubsub/issues/997 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/434381c089e42902b5400ef3abd9900fc99f6e1cbc9ca1ef1481a3ae64f03786/googleapis/python-pubsub/issues/997 |
| og:image:alt | Environment details OS type and version: Ubuntu 22.04 Python version: 3.11 pip version: 23.0.1 google-cloud-pubsub version: 2.18.4 Steps to reproduce Run code sample indefinitely Sometime it shows ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | hson2 |
| hostname | github.com |
| expected-hostname | github.com |
| None | 030096ee0db095447bfe77409d33bfac127ca7128299c58deef27c52eaa1b1f0 |
| turbo-cache-control | no-preview |
| go-import | github.com/googleapis/python-pubsub git https://github.com/googleapis/python-pubsub.git |
| octolytics-dimension-user_id | 16785467 |
| octolytics-dimension-user_login | googleapis |
| octolytics-dimension-repository_id | 226992581 |
| octolytics-dimension-repository_nwo | googleapis/python-pubsub |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 226992581 |
| octolytics-dimension-repository_network_root_nwo | googleapis/python-pubsub |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | e8506f6d0538364886e3f0153c154c410965e70d |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width