)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"20d5308e49c36a9e1810cff69dc9e8b149534720","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"e85ceaf2_97802bca","updated":"2025-03-27 15:29:19.000000000","message":"I will add a release note shortly in this patch.\nTests for the new threading backend will come in a separate follow-up patch.","commit_id":"7a8b71e904338c33a7bd0f61f96ed9604fd2771b"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"837bb4d77c47cc35b43c44d4562c7ed58e371849","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"505247d8_c137da31","updated":"2025-03-28 17:23:36.000000000","message":"Fixing the PEP8 errors would apprently give you a verified +1","commit_id":"134b27d0237b5beb50d3fd820d84296414eb8452"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"6e15284837ddcb28171d830f61e3ca3f5f64c03f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"3e7cc18d_950b85bb","updated":"2025-04-22 14:40:11.000000000","message":"Hey Daniel,\n\nI made some inline comments, I think you missed to expose some logic of the new backend, see my inline comment.\n\nDo you have updates concerning all these PEP8 errors? That would be good to have fixed before starting deep reviews.\n\nI\u0027d also suggest to add a release note concerning the addition of this new backend, that\u0027s a key point of the migration, so IMO this is important to have it in our changelog.\n\nWaiting for your updates to continue the reviews.\n\nThanks for your work.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"e2eb55ceec4697fb0cd5c15f601397d3ef079e29","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"116ac99a_8bfc678e","updated":"2025-04-23 12:48:33.000000000","message":"I\u0027d have separated the indentation changes from the logic change (the threading backend implementation).","commit_id":"edd27a7613ef9997f9eb1796b3050d17996878cb"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"f86b7bb76aebd1590f34c6b17dab77b005f1f8c8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"1da664af_537a731e","updated":"2025-04-23 12:46:40.000000000","message":"Nice job with pep8 errors, thanks, unfortunatelly 3 errors pep8 errors remains.\nAlso I still think we have a problem with the exposed components from the threading backend, please see my inline comment.","commit_id":"edd27a7613ef9997f9eb1796b3050d17996878cb"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"4f81913e983ca6d93fd1f7bd4048d0fa5a0c37b2","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":9,"id":"6091f193_113aaaf8","updated":"2025-04-23 18:44:56.000000000","message":"While working on https://review.opendev.org/c/openstack/networking-baremetal/+/947985 I noticed I\u0027m basically stuck waiting for a threading backend to land, I saw this change and gave it a shot.\n\nAttributeError: module \u0027oslo_service.backend.threading.service\u0027 has no attribute \u0027Launcher\u0027. Did you mean: \u0027launch\u0027?\n\nis the error I got when trying to set the backend, via init_backend(THREADING) in __init__.py. I assume it\u0027s due to the incomplete nature of this change but just letting you know.\n\nFeel free to reach out to me (JayF) or CID (cid) on IRC if you\u0027d like us to change something in that networking-baremetal patch to be a better test case for you.\n\nThanks!","commit_id":"a9c5900c1546e745141793b7964c096e1f3ac54f"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"22486f9e8ed4615bc64d7543e855e9e2cc373648","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"5316ed2a_9a6c4d33","updated":"2025-04-28 08:10:09.000000000","message":"That would be awesome to also have functional tests, because for now we have no real usages of the threading backend in tests.","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"8b9d5addd3b1ab07b240a242bcfb0beba26124ca","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"c8737c3d_5f7f3756","updated":"2025-04-28 12:47:55.000000000","message":"@Daniel: Please can you either rename your local branch or git review with the topic set to \"eventlet-removal\", this way it will avoid to change the topic each time you push a new patch set.","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"102e469ee62372a0ea6761552545fcd25e603953","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"3eaa9f66_0d649850","updated":"2025-04-28 16:13:24.000000000","message":"Locally with https://review.opendev.org/c/openstack/nova/+/948311 and https://review.opendev.org/c/openstack/oslo.service/+/948310 together I was able to start nova-scheduler in fully native threading mode and I was able to schedule a VM.","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fbcf7b6ec8a4baf0cce089a8516a5a469368338c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"2928ec28_944df140","in_reply_to":"3eaa9f66_0d649850","updated":"2025-05-02 11:52:10.000000000","message":"I will check that. Thanks a lot!","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"80c79c1a9c71e18593755aa06574e73776260acc","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":12,"id":"a5e7b46a_a0d6ad72","updated":"2025-04-30 13:42:52.000000000","message":"I put a -1 to highlight all the previous comments made against this patch.\n\nIn short I think we have to address the following items:\n\n## 1. Technical failures\n\nI think many questions/problems remains relevant.\nPlease close the comments that you think that you have already addressed.\nI think you have to squash all the adjustments made by gibi on the following patch in your patch to have a functional backend. \n\nGibi\u0027s blog post well summarize the state of the art of using your changes, it should give you the things that remains to be done: https://gibizer.github.io/posts/Eventlet-Removal-Scheduler-First-Run/\n\n## 2. Missing requirements\n\nConcerning the requirements job failure, you missed to add a lower bound for futurist and cotyledon, and as I said in my previous comment, I think you have to migrate the extra requirements into the setup.cfg file.\n\n## 3. The release note\n\nI still think that we need a release note.\n\n## 4. Branch naming convention and tracking the topic\n\nTo finish, please do not forget to rename your branch, or to git review with the eventlet-removal topic set as I asked you previously, that will avoid setting it manually at each new patch set.","commit_id":"712a7f47830a291f32f74129816d4ea6b3baaeb2"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"ef2a3d473d8f4508d5d0457070760d598a043b7c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":15,"id":"5251d7a0_9698bdc8","updated":"2025-05-05 07:29:40.000000000","message":"Thanks Daniel.\n\nLGTM:\n- All the fixes proposed by gibi seems fixed up here;\n- all the comments have been addressed;\n- the release note is included;\n- the missing requirements problem is now fixed;\n- CI is green.\n\nI left an in-line comment concerning the content of the release note.\n\n+1 for now by waiting for your answer to the questions below.\n\nWhat is your plan with the functional test? Do you plan to add them with a follow up patch?\n\nConcerning the doc, I suppose you will soon come back on https://review.opendev.org/c/openstack/oslo.service/+/940664, isn\u0027t?","commit_id":"eec7410991acde81c2c136a3c8e6a203193dbd9a"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"d90363ffd2831edea978e95121bdbbfa7ba81e60","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":15,"id":"b5ca983a_c4c8015d","in_reply_to":"5251d7a0_9698bdc8","updated":"2025-05-05 10:04:14.000000000","message":"Yes I would like to do a follow up patch for the functional and unit tests. Yes for the documentation I will work back on that patch. Thanks a lot for the code review!","commit_id":"eec7410991acde81c2c136a3c8e6a203193dbd9a"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"18904b6c00510d59a553a8f47b9b64f8a27e2361","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"fb5d6632_f0eaf102","updated":"2025-05-06 12:14:09.000000000","message":"As far as I see we currently using os.fork(), hidden in cotyledon, to start the worker processes. Now the master process might have threads. The os.fork doc [1] says:\n\u003e Even in code that appears to work, it has never been safe to mix threading with os.fork() on POSIX platforms. The CPython runtime itself has always made API calls that are not safe for use in the child process when threads existed in the parent (such as malloc and free).\n\nAlso [2] states the in 3.14 the default start method will change from fork to spawn.\n\nSpawn is slower but safer than fork as the child process does not inherit the state of the parent process see[2].\n\nI observed in nova that if a module level ThreadPoolExecutor is initialized in the master process before the fork of the workers then the workers are inherited the copy of the global executor\u0027s state variables and started behaving incorrectly. \n\nWith all these known I suggests to switch from \"fork\" to \"spawn\" with set_start_method[3].\n\nBut doing so leads to error when creating the worker processes.\n\n```\nMay 06 11:49:15 aio nova-scheduler[15933]: Exception in thread Thread-8 (_child_supervisor_thread):\nMay 06 11:49:15 aio nova-scheduler[15933]: Traceback (most recent call last):\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/threading.py\", line 1073, in _bootstrap_inner\nMay 06 11:49:15 aio nova-scheduler[15933]:     self.run()\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/threading.py\", line 1010, in run\nMay 06 11:49:15 aio nova-scheduler[15933]:     self._target(*self._args, **self._kwargs)\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service_manager.py\", line 256, in _child_supervisor_thread\nMay 06 11:49:15 aio nova-scheduler[15933]:     self._adjust_workers()\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service_manager.py\", line 343, in _adjust_workers\nMay 06 11:49:15 aio nova-scheduler[15933]:     self._start_worker(service_id, worker_id)\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service_manager.py\", line 414, in _start_worker\nMay 06 11:49:15 aio nova-scheduler[15933]:     p \u003d _utils.spawn_process(\nMay 06 11:49:15 aio nova-scheduler[15933]:         ^^^^^^^^^^^^^^^^^^^^^\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_utils.py\", line 80, in spawn_process\nMay 06 11:49:15 aio nova-scheduler[15933]:     p.start()\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/process.py\", line 121, in start\nMay 06 11:49:15 aio nova-scheduler[15933]:     self._popen \u003d self._Popen(self)\nMay 06 11:49:15 aio nova-scheduler[15933]:                   ^^^^^^^^^^^^^^^^^\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/context.py\", line 224, in _Popen\nMay 06 11:49:15 aio nova-scheduler[15933]:     return _default_context.get_context().Process._Popen(process_obj)\nMay 06 11:49:15 aio nova-scheduler[15933]:            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/context.py\", line 289, in _Popen\nMay 06 11:49:15 aio nova-scheduler[15933]:     return Popen(process_obj)\nMay 06 11:49:15 aio nova-scheduler[15933]:            ^^^^^^^^^^^^^^^^^^\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/popen_spawn_posix.py\", line 32, in __init__\nMay 06 11:49:15 aio nova-scheduler[15933]:     super().__init__(process_obj)\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/popen_fork.py\", line 19, in __init__\nMay 06 11:49:15 aio nova-scheduler[15933]:     self._launch(process_obj)\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/popen_spawn_posix.py\", line 47, in _launch\nMay 06 11:49:15 aio nova-scheduler[15933]:     reduction.dump(process_obj, fp)\nMay 06 11:49:15 aio nova-scheduler[15933]:   File \"/usr/lib/python3.12/multiprocessing/reduction.py\", line 60, in dump\nMay 06 11:49:15 aio nova-scheduler[15933]:     ForkingPickler(file, protocol).dump(obj)\nMay 06 11:49:15 aio nova-scheduler[15933]: AttributeError: Can\u0027t pickle local object \u0027_ConfigFileOpt.__init__.\u003clocals\u003e.\u003clambda\u003e\u0027\n```\n\nIf I have to guess `_ConfigFileOpt.__init__.\u003clocals\u003e.\u003clambda\u003e` is from https://github.com/openstack/oslo.config/blob/d6e5c96d6dbeec0db974dfb8afc8e508b74861e5/oslo_config/cfg.py#L1387\n\n\n[1]https://docs.python.org/3/library/os.html#os.fork\n[2]https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods\n[3]https://docs.python.org/3/library/multiprocessing.html#multiprocessing.set_start_method","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"45c1ec037bbf01e3c04113f1db98f87534b4d123","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"e144d4a0_3d536aec","updated":"2025-05-06 12:20:57.000000000","message":"Remove my vote to highlight gibi\u0027s last comment","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"2434b3f20b42474a6e3f51e7fbd79b54c76af595","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"26b4cb39_c2250e91","updated":"2025-05-05 11:41:52.000000000","message":"Thanks Daniel for your previous answers. Accordingly to Daniel\u0027s previous response about documentation and testing, I think we are ready to merge this patch. This way, we will be able to go futher with the integration with service and the new backend.\n\nI\u0027d suggest to give next the priority to finishing the documentation, to allow services to manage their migration and to allow them to get a better understanding of the mechanisms introduced by the backend notion.","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"249c9ba5ce6029d2064ce29aee42e2706d66ab19","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"ac7ab07b_a61595b6","in_reply_to":"4e545d1a_5f6f19a7","updated":"2025-05-12 10:24:19.000000000","message":"Thanks a lot!\nYes, I agree switching to spawn would be tricky right now with the current architecture and the lambda issues in config. That’s also why I added no_fork — just to have a safer option when forking isn’t ideal.\n\nMaybe one day we’ll support spawn properly, but for now I think this gives us something solid to build on.","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"6e189f9c00578b87a9c1fc9b38b342f9517737fe","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"7568a701_59f62c3c","in_reply_to":"4f00df06_4484b3d9","updated":"2025-05-06 14:28:15.000000000","message":"We discussed couple options:\n* switch from os.fork to os.spawn and fix whathever needed to make it work (i.e. at least oslo.config pickle issue above)\n* client\u0027s can manually detect the fork and re-init whats needed (see my example of this is in https://review.opendev.org/c/openstack/nova/+/947966/8/nova/utils.py#1276)\n* forbid on the client side to ever initialize threading in the master process. (probably hard to implement in nova and hard to enforce in oslo) so fork than work.\n* support a mode where do not fork or spawn at all just use the master process for the service, and assume that the service uses thread pool(s) as needed.\n\nSee discussion in https://meetings.opendev.org/irclogs/%23openstack-nova/%23openstack-nova.2025-05-06.log.html#openstack-nova.2025-05-06.log.html#t2025-05-06T12:18:18","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"3d41ea644eb405d22e7e0bb9d19247f061cb6923","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"75800400_adcabe79","in_reply_to":"7568a701_59f62c3c","updated":"2025-05-07 11:33:51.000000000","message":"Hi gibi,\n\nThanks a lot for the feedback. I have added support for no_fork as an optional mode to run the service in the main thread when needed.\nI have also updated the release note accordingly. Let me know if there’s anything else you’d like me to adjust.","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"fc411fe0e220bb8f9d5c497e0a5da1327c3e8e45","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"4e545d1a_5f6f19a7","in_reply_to":"75800400_adcabe79","updated":"2025-05-12 07:43:47.000000000","message":"@dbengt@redhat.com Thanks for working on this. The no_fork option is good for services where we cannot / don\u0027t want to have multiple processes to scale a service over a single CPU (due to the GIL). At the moment (see my detailed comment inline) I don\u0027t think we can easily move to os.spawn due to the architecture we have and the limitation of pythons pickle module. So I guess this is all we can do for now.","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"15b9d3e38860abbb8f17d8e1ab8c2c92fc7c2f9f","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"4f00df06_4484b3d9","in_reply_to":"fb5d6632_f0eaf102","updated":"2025-05-06 12:14:32.000000000","message":"marked unsolved","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"fc411fe0e220bb8f9d5c497e0a5da1327c3e8e45","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":20,"id":"34daf957_ff4d1430","updated":"2025-05-12 07:43:47.000000000","message":"Functionally this patch works from me (see nova-next CI job running with threaded nova-scheduler in https://review.opendev.org/c/openstack/nova/+/948450/9). I have couple of comments inline that can be fixed in a follow up. But I see that Takashi also left comments so I think it is worth to re-spin the review anyhow.","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"c291781b99d99cff763eeedbb2ef1297a24e03cd","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":20,"id":"c4d2e2bd_de0eef86","in_reply_to":"34daf957_ff4d1430","updated":"2025-05-12 10:08:21.000000000","message":"Hi gibi,\n\nThanks a lot, I really appreciate the tests and feedback you’ve provided.\nGreat to hear that it worked functionally for you!\n\nI will go through all the comments carefully. Depending on how critical Takashi’s feedback is, I might propose merging the patch first and handling the remaining improvements step by step, just to get the new backend in and start iterating from there.\n\nThanks again!","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"7d285e739b2928c84229a5add5cdfbf840c89f6f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":24,"id":"6fb37c77_65cd1bbe","updated":"2025-05-12 14:41:52.000000000","message":"I\u0027m happy to work through any issues with these changes as bugs against oslo.service. Eager to get an implementation merged so we can try to use it :D","commit_id":"e81d891ea141f9dc60e7e0c55266aad7dfa21505"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"a5fa6048dd6c016087ca5e96b8db9988ecf00be9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":28,"id":"1e3246c7_1babfc48","updated":"2025-05-13 08:17:50.000000000","message":"Hey, thanks for all these latest updates.\nConcerning myself, I\u0027m ok to merge it and continue with follow ups if bugs are found.\n\nBefore merging I\u0027d just suggest to fix the following comment, because it is easy to fix and strongly related to the addition of cotyledon into oslo.service:\nhttps://review.opendev.org/c/openstack/oslo.service/+/945720/10..28/oslo_service/backend/threading/service.py#b90\n\nThanks in advance.","commit_id":"ce1ea32c4a674c7223507cdd50363852deafa777"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":28,"id":"32c9e075_f7a120d6","updated":"2025-05-13 10:39:42.000000000","message":"No objections to merging it as it is, although I doubt we\u0027ll be able to use the initial version in Ironic (see inline comments)","commit_id":"ce1ea32c4a674c7223507cdd50363852deafa777"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"f24060e04d81f07be3fb059a3762c7074d67c1e3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":28,"id":"43ec8235_7b2ebd52","in_reply_to":"1e3246c7_1babfc48","updated":"2025-05-13 09:54:01.000000000","message":"Here are example of how to implement it https://review.opendev.org/c/openstack/octavia/+/454873/9/octavia/cmd/octavia_worker.py\n\nIMO that\u0027s a pretty easy adjustment.","commit_id":"ce1ea32c4a674c7223507cdd50363852deafa777"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"c2e678f5ee151bf9d1aa27afdfa150a908033050","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":29,"id":"2967fa5a_48d6bb98","updated":"2025-05-14 05:50:19.000000000","message":"Hi Daniel. I\u0027m leaving a -1 just for visibility.\n\nI\u0027m still seeing some errors when using the threading backend. From the Neutron patch [1].\n\nLog: https://142701e3b4df6dd24454-85bb929ac58f1a419407783b8f581cf5.ssl.cf1.rackcdn.com/openstack/2d455b7d2142490d8accdbda0451884a/controller/logs/screen-q-l3.txt\n\nSnippet: https://paste.opendev.org/show/bAaG04bNk31diPoJXxKJ/\n\nI\u0027m using cotyledon\u003d\u003d\u003d2.0.0\n\n[1]https://review.opendev.org/c/openstack/neutron/+/938404","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"58638c53cf14a2f7ed3e6895f578ae4ece8d338c","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":29,"id":"70bf2855_0db0d4ff","updated":"2025-05-13 11:35:06.000000000","message":"LGTM as it is, and I\u0027m ok if we continuie this topic through follow up patches and launchpad bugs. Just waiting the CI and if jobs are successful I\u0027ll transform my vote in a +2.","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"df97fe53c2093aad96931da9d2969bf1a9e1082f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":29,"id":"383f2a1b_0979afc6","updated":"2025-05-13 11:37:46.000000000","message":"Note: some of my comments assumed revision 26 was the latest (because gerrit). Some still apply though.","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":29,"id":"472df3b8_b0b1924e","updated":"2025-05-13 11:44:01.000000000","message":"Re-adding still valid comments. I\u0027m okay with a follow-up.","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"e25f29cf64c4f859c36e71035a1d53d1a6d76f5e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":29,"id":"4e61ac9c_06cdcb5b","in_reply_to":"2967fa5a_48d6bb98","updated":"2025-05-14 09:19:22.000000000","message":"Apparently this error [1] seems related to the latest addition that I requested yesterday [2]. Something surely went wrong within the integration of the `cotyledon.oslo_config_glue` module\n\n[1] https://paste.opendev.org/show/bAaG04bNk31diPoJXxKJ/\n[2] https://review.opendev.org/c/openstack/oslo.service/+/945720/comments/1e3246c7_1babfc48","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"c1cf65a3912a1661dc54de081e50f62a386cd21c","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":29,"id":"9ee7dd99_28787a21","in_reply_to":"4e61ac9c_06cdcb5b","updated":"2025-05-14 09:22:11.000000000","message":"I wonder if the order of statements matters, see the example here https://review.opendev.org/c/openstack/octavia/+/454873/9/octavia/cmd/octavia_worker.py","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"4e25bfc9ea0e52776453e6d2daa23b819006d0a3","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":29,"id":"be9c7fac_af7f3d93","in_reply_to":"9ee7dd99_28787a21","updated":"2025-05-14 09:39:12.000000000","message":"Thanks a lot! Yes it was the issue and it\u0027s fixed now.","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"7a8825456fd7c46eab004c8a98dad4e0d086e7e8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":29,"id":"21fd87a3_c66cad16","in_reply_to":"be9c7fac_af7f3d93","updated":"2025-05-14 09:39:24.000000000","message":"Done","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"defb688eb274339288b6f2fd4e4b9eb071257763","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":31,"id":"a15e4832_3d25f1b7","updated":"2025-05-21 09:52:42.000000000","message":"I\u0027m still concerned with adding multiple public api in oslo_service.backend.common as we may not be allowed to refactor these after a new release, but given the fact that some active works are pending on this I\u0027ll merge this now.","commit_id":"5de514f1f851412b18793c88289f7d2b01e5f217"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"7c12de46b7f4020e1ffeb68d2648901c3e5be37d","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":31,"id":"95c6c6e3_730f83a0","updated":"2025-05-19 14:00:02.000000000","message":"Local testing with https://review.opendev.org/c/openstack/nova/+/948450/17 shows no problems to me. I agree that land this as is, then release it so the services can start consuming it properly. Then follow ups can be pushed and released separately.","commit_id":"5de514f1f851412b18793c88289f7d2b01e5f217"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"8150aeaaad45c47a2e9f2a56c0fe4170bb6766fe","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":31,"id":"3856150c_74733cd8","updated":"2025-05-15 07:54:30.000000000","message":"Still lgtm but please do collect the comments and address them in a follow-up.","commit_id":"5de514f1f851412b18793c88289f7d2b01e5f217"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"347eda85023b898ab7b5bbfb3ce89c3854487e5c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":31,"id":"6d7cfe89_af2c8a3c","updated":"2025-05-14 14:46:48.000000000","message":"recheck","commit_id":"5de514f1f851412b18793c88289f7d2b01e5f217"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"986189d84448f651b5546d585bb678c74043708e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":31,"id":"8e5856d1_84e60504","in_reply_to":"95c6c6e3_730f83a0","updated":"2025-05-20 07:47:54.000000000","message":"Same here (Neutron, L3 agent migration): https://review.opendev.org/c/openstack/neutron/+/938404","commit_id":"5de514f1f851412b18793c88289f7d2b01e5f217"}],"oslo_service/backend/__init__.py":[{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"fc411fe0e220bb8f9d5c497e0a5da1327c3e8e45","unresolved":true,"context_lines":[{"line_number":75,"context_line":"    _backend_hook \u003d None"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"def init_backend(type_: BackendType) -\u003e None:"},{"line_number":79,"context_line":"    \"\"\"Establish which backend will be used when get_backend() is called.\"\"\""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    global _cached_backend, _cached_components, _cached_backend_type"}],"source_content_type":"text/x-python","patch_set":20,"id":"2c57f6c3_563133e7","line":78,"updated":"2025-05-12 07:43:47.000000000","message":"I would like to ask for a bit of addition here or in a follow up commit. \n\nAs init_backend can only be called once nova needs a way to not call it multiple times if it is already set properly and fail if it is set but not for the desired value. \n\nSee [1] about the WIP code I\u0027m working with in nova now.\n\nSo either allow init_backend to be called multiple times with the same value. Or add a get_backend_type() call that returns the type name set or None.\n\n[1]https://review.opendev.org/c/openstack/nova/+/948311/15/nova/monkey_patch.py#98","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"78add28ea7e8813db678fb950d954c05f5bafec4","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    _backend_hook \u003d None"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"def init_backend(type_: BackendType) -\u003e None:"},{"line_number":79,"context_line":"    \"\"\"Establish which backend will be used when get_backend() is called.\"\"\""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    global _cached_backend, _cached_components, _cached_backend_type"}],"source_content_type":"text/x-python","patch_set":20,"id":"79c63aa6_31bd12b9","line":78,"in_reply_to":"211567ba_37cd3bb6","updated":"2025-05-13 00:11:34.000000000","message":"Done","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"249c9ba5ce6029d2064ce29aee42e2706d66ab19","unresolved":true,"context_lines":[{"line_number":75,"context_line":"    _backend_hook \u003d None"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"def init_backend(type_: BackendType) -\u003e None:"},{"line_number":79,"context_line":"    \"\"\"Establish which backend will be used when get_backend() is called.\"\"\""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    global _cached_backend, _cached_components, _cached_backend_type"}],"source_content_type":"text/x-python","patch_set":20,"id":"211567ba_37cd3bb6","line":78,"in_reply_to":"2c57f6c3_563133e7","updated":"2025-05-12 10:24:19.000000000","message":"Thanks a lot for the suggestion!\n\nYes, that makes total sense. I think the cleanest would be to add a get_backend_type() helper it avoids the need to wrap init_backend() with try/except and makes the intent clearer.\n\nI can add that in a follow-up patch right after this one is merged (or include it now if you think it’s better to do it in the same review).","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"}],"oslo_service/backend/common/daemon_utils.py":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright (C) 2025 Red Hat, Inc."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\");"},{"line_number":4,"context_line":"# you may not use this file except in compliance with the License."}],"source_content_type":"text/x-python","patch_set":19,"id":"f507da32_8aaa7343","line":1,"updated":"2025-05-07 13:01:50.000000000","message":"If these common modules are all used by the service modules then can we create the single service.py and define everything in that file? It may make the file structure simpler rather than having only a few interfaces per file","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"554413dac1e030ffed8329f002a0448a19ac04dc","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright (C) 2025 Red Hat, Inc."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\");"},{"line_number":4,"context_line":"# you may not use this file except in compliance with the License."}],"source_content_type":"text/x-python","patch_set":19,"id":"629c67b2_a6f5ae77","line":1,"in_reply_to":"0a57585a_edfbfc7a","updated":"2025-05-12 11:59:14.000000000","message":"The change may affects public api so follow-up should be merged in the same release.\nI\u0027m ok with leaving it for follow-up but that likely means we can\u0027t merge this before milestone-1.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cfa8be8f4e0f89fb6fd6447565eab043420c9823","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright (C) 2025 Red Hat, Inc."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\");"},{"line_number":4,"context_line":"# you may not use this file except in compliance with the License."}],"source_content_type":"text/x-python","patch_set":19,"id":"0a57585a_edfbfc7a","line":1,"in_reply_to":"f507da32_8aaa7343","updated":"2025-05-12 10:45:53.000000000","message":"Yes, makes sense. I split them out thinking they’d be reused, but they are only used in service.py. I can move them there, ok for a follow-up patch after this one?","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"}],"oslo_service/backend/threading/__init__.py":[{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"6e15284837ddcb28171d830f61e3ca3f5f64c03f","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":33,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":34,"context_line":"            \"Service\": service.Service,"},{"line_number":35,"context_line":"            \"ServiceWrapper\": service.ServiceWrapper,"},{"line_number":36,"context_line":"            # Looping call-related classes"},{"line_number":37,"context_line":"            \"LoopingCallBase\": loopingcall.LoopingCallBase,"},{"line_number":38,"context_line":"            \"LoopingCallDone\": loopingcall.LoopingCallDone,"}],"source_content_type":"text/x-python","patch_set":6,"id":"e96ddcf0_3c2cc5cd","line":35,"range":{"start_line":35,"start_character":12,"end_line":35,"end_character":53},"updated":"2025-04-22 14:40:11.000000000","message":"I don\u0027t know if this is intentional or not, but apparently, the following entries are missing:\n\n- SignalHandler\n- SignalExit\n- Singleton\n- _is_daemon\n- _is_sighup_and_daemon\n\nAll these components are exposed by https://opendev.org/openstack/oslo.service/src/branch/master/oslo_service/service.py and they are also part of the eventlet backend (https://opendev.org/openstack/oslo.service/src/branch/master/oslo_service/backend/eventlet/__init__.py), so I suppose we also need them here.\n\nPlus, they are defined in oslo_service/backend/threading/service.py, so IMO they should be exposed here.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"b572ce2056e2d12feda7b07365573611d921c5f0","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":33,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":34,"context_line":"            \"Service\": service.Service,"},{"line_number":35,"context_line":"            \"ServiceWrapper\": service.ServiceWrapper,"},{"line_number":36,"context_line":"            # Looping call-related classes"},{"line_number":37,"context_line":"            \"LoopingCallBase\": loopingcall.LoopingCallBase,"},{"line_number":38,"context_line":"            \"LoopingCallDone\": loopingcall.LoopingCallDone,"}],"source_content_type":"text/x-python","patch_set":6,"id":"8b86c9e7_ab8e4be0","line":35,"range":{"start_line":35,"start_character":12,"end_line":35,"end_character":53},"in_reply_to":"3c3386b3_27fe7edd","updated":"2025-04-23 14:48:28.000000000","message":"Yes, still working on it! Thanks a lot I have done a big refactor and pulled out a bunch of common stuff, the fix is coming soon!","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"79f71f8c0f8240e7dd95bc2388a4ddbd5f2c7d8d","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":33,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":34,"context_line":"            \"Service\": service.Service,"},{"line_number":35,"context_line":"            \"ServiceWrapper\": service.ServiceWrapper,"},{"line_number":36,"context_line":"            # Looping call-related classes"},{"line_number":37,"context_line":"            \"LoopingCallBase\": loopingcall.LoopingCallBase,"},{"line_number":38,"context_line":"            \"LoopingCallDone\": loopingcall.LoopingCallDone,"}],"source_content_type":"text/x-python","patch_set":6,"id":"8d293384_0bc48751","line":35,"range":{"start_line":35,"start_character":12,"end_line":35,"end_character":53},"in_reply_to":"8b86c9e7_ab8e4be0","updated":"2025-04-23 14:49:24.000000000","message":"ack, thanks for your feedback","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"3ed5d80771d7d55ceb31f5961b7088b2e430cb5d","unresolved":false,"context_lines":[{"line_number":32,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":33,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":34,"context_line":"            \"Service\": service.Service,"},{"line_number":35,"context_line":"            \"ServiceWrapper\": service.ServiceWrapper,"},{"line_number":36,"context_line":"            # Looping call-related classes"},{"line_number":37,"context_line":"            \"LoopingCallBase\": loopingcall.LoopingCallBase,"},{"line_number":38,"context_line":"            \"LoopingCallDone\": loopingcall.LoopingCallDone,"}],"source_content_type":"text/x-python","patch_set":6,"id":"90a3f590_740439f8","line":35,"range":{"start_line":35,"start_character":12,"end_line":35,"end_character":53},"in_reply_to":"8d293384_0bc48751","updated":"2025-04-23 14:49:49.000000000","message":"Done","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"f86b7bb76aebd1590f34c6b17dab77b005f1f8c8","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":33,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":34,"context_line":"            \"Service\": service.Service,"},{"line_number":35,"context_line":"            \"ServiceWrapper\": service.ServiceWrapper,"},{"line_number":36,"context_line":"            # Looping call-related classes"},{"line_number":37,"context_line":"            \"LoopingCallBase\": loopingcall.LoopingCallBase,"},{"line_number":38,"context_line":"            \"LoopingCallDone\": loopingcall.LoopingCallDone,"}],"source_content_type":"text/x-python","patch_set":6,"id":"3c3386b3_27fe7edd","line":35,"range":{"start_line":35,"start_character":12,"end_line":35,"end_character":53},"in_reply_to":"e96ddcf0_3c2cc5cd","updated":"2025-04-23 12:46:40.000000000","message":"My remark is still valid even with the latest patch sets you just pushed.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"28034085c92a832d586255f5f31ea9b1aa88e77e","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            # Service-related classes"},{"line_number":33,"context_line":"            \"ServiceBase\": service.Service,"},{"line_number":34,"context_line":"            \"ServiceLauncher\": service.ProcessLauncher,"},{"line_number":35,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":36,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":37,"context_line":"            \"Service\": service.Service,"},{"line_number":38,"context_line":"            \"Services\": service.Services,"}],"source_content_type":"text/x-python","patch_set":10,"id":"96f2532e_1518d3fd","line":35,"updated":"2025-04-26 15:26:42.000000000","message":"When I try to use this patch I get\n```\n  File \"/home/gibi/upstream/git/openstack/oslo.service/oslo_service/backend/__init__.py\", line 79, in init_backend\n    _cached_components \u003d new_backend.get_service_components()\n                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/home/gibi/upstream/git/openstack/oslo.service/oslo_service/backend/threading/__init__.py\", line 35, in get_service_components\n    \"Launcher\": service.Launcher,\n                ^^^^^^^^^^^^^^^^\nAttributeError: module \u0027oslo_service.backend.threading.service\u0027 has no attribute \u0027Launcher\u0027. Did you mean: \u0027launch\u0027?\n```","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fbcf7b6ec8a4baf0cce089a8516a5a469368338c","unresolved":false,"context_lines":[{"line_number":32,"context_line":"            # Service-related classes"},{"line_number":33,"context_line":"            \"ServiceBase\": service.Service,"},{"line_number":34,"context_line":"            \"ServiceLauncher\": service.ProcessLauncher,"},{"line_number":35,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":36,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":37,"context_line":"            \"Service\": service.Service,"},{"line_number":38,"context_line":"            \"Services\": service.Services,"}],"source_content_type":"text/x-python","patch_set":10,"id":"d896a275_a5b80dba","line":35,"in_reply_to":"6077354e_f031dfc1","updated":"2025-05-02 11:52:10.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4691217c9859bf152354ea9183cd5797eebff795","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            # Service-related classes"},{"line_number":33,"context_line":"            \"ServiceBase\": service.Service,"},{"line_number":34,"context_line":"            \"ServiceLauncher\": service.ProcessLauncher,"},{"line_number":35,"context_line":"            \"Launcher\": service.Launcher,"},{"line_number":36,"context_line":"            \"ProcessLauncher\": service.ProcessLauncher,"},{"line_number":37,"context_line":"            \"Service\": service.Service,"},{"line_number":38,"context_line":"            \"Services\": service.Services,"}],"source_content_type":"text/x-python","patch_set":10,"id":"6077354e_f031dfc1","line":35,"in_reply_to":"96f2532e_1518d3fd","updated":"2025-04-26 15:27:34.000000000","message":"Ah I see @jay@jvf.cc hit the same issue.","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"}],"oslo_service/backend/threading/loopingcall.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":184,"context_line":""},{"line_number":185,"context_line":"        # Use futurist\u0027s ThreadPoolExecutor to run the loop in a background"},{"line_number":186,"context_line":"        # thread."},{"line_number":187,"context_line":"        executor \u003d futurist.ThreadPoolExecutor(max_workers\u003d1)"},{"line_number":188,"context_line":"        self._future \u003d executor.submit(_run_loop)"},{"line_number":189,"context_line":"        self._future.add_done_callback(self._on_done)"},{"line_number":190,"context_line":"        return self.done"}],"source_content_type":"text/x-python","patch_set":26,"id":"eb404e3c_a5baabb9","line":187,"updated":"2025-05-13 10:39:42.000000000","message":"having a thread pool for just one short-lived thread seems like an overkill. You can just run _run_loop in a daemon thread","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"}],"oslo_service/backend/threading/service.py":[{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"6e15284837ddcb28171d830f61e3ca3f5f64c03f","unresolved":true,"context_lines":[{"line_number":210,"context_line":"        exit_code \u003d manager.run()"},{"line_number":211,"context_line":"        return exit_code"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def stop(self):"},{"line_number":214,"context_line":"        # Cotyledon manages termination via ServiceWrapper. Additional logic"},{"line_number":215,"context_line":"        # can be added here if needed."},{"line_number":216,"context_line":"        pass"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    def wait(self):"},{"line_number":219,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":220,"context_line":"        # is required."},{"line_number":221,"context_line":"        pass"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"class Service(ServiceBase):"}],"source_content_type":"text/x-python","patch_set":6,"id":"54ded9e7_856b6089","line":221,"range":{"start_line":213,"start_character":0,"end_line":221,"end_character":12},"updated":"2025-04-22 14:40:11.000000000","message":"Do we need to define them if these logics are already managed by cotyledon?","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"f86b7bb76aebd1590f34c6b17dab77b005f1f8c8","unresolved":true,"context_lines":[{"line_number":210,"context_line":"        exit_code \u003d manager.run()"},{"line_number":211,"context_line":"        return exit_code"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def stop(self):"},{"line_number":214,"context_line":"        # Cotyledon manages termination via ServiceWrapper. Additional logic"},{"line_number":215,"context_line":"        # can be added here if needed."},{"line_number":216,"context_line":"        pass"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    def wait(self):"},{"line_number":219,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":220,"context_line":"        # is required."},{"line_number":221,"context_line":"        pass"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"class Service(ServiceBase):"}],"source_content_type":"text/x-python","patch_set":6,"id":"3e81a4d5_8cb67037","line":221,"range":{"start_line":213,"start_character":0,"end_line":221,"end_character":12},"in_reply_to":"2a77c195_2d37300b","updated":"2025-04-23 12:46:40.000000000","message":"Ok, thanks for details.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"20ce4c236c18afb03d1a973abb7347644d0fd1da","unresolved":false,"context_lines":[{"line_number":210,"context_line":"        exit_code \u003d manager.run()"},{"line_number":211,"context_line":"        return exit_code"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def stop(self):"},{"line_number":214,"context_line":"        # Cotyledon manages termination via ServiceWrapper. Additional logic"},{"line_number":215,"context_line":"        # can be added here if needed."},{"line_number":216,"context_line":"        pass"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    def wait(self):"},{"line_number":219,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":220,"context_line":"        # is required."},{"line_number":221,"context_line":"        pass"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"class Service(ServiceBase):"}],"source_content_type":"text/x-python","patch_set":6,"id":"a8931f9d_24ca3724","line":221,"range":{"start_line":213,"start_character":0,"end_line":221,"end_character":12},"in_reply_to":"3e81a4d5_8cb67037","updated":"2025-04-23 14:48:22.000000000","message":"Done","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"b572ce2056e2d12feda7b07365573611d921c5f0","unresolved":true,"context_lines":[{"line_number":210,"context_line":"        exit_code \u003d manager.run()"},{"line_number":211,"context_line":"        return exit_code"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def stop(self):"},{"line_number":214,"context_line":"        # Cotyledon manages termination via ServiceWrapper. Additional logic"},{"line_number":215,"context_line":"        # can be added here if needed."},{"line_number":216,"context_line":"        pass"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    def wait(self):"},{"line_number":219,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":220,"context_line":"        # is required."},{"line_number":221,"context_line":"        pass"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"class Service(ServiceBase):"}],"source_content_type":"text/x-python","patch_set":6,"id":"47e9af9b_3875521d","line":221,"range":{"start_line":213,"start_character":0,"end_line":221,"end_character":12},"in_reply_to":"3e81a4d5_8cb67037","updated":"2025-04-23 14:48:28.000000000","message":"You\u0027re welcome!","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"3ed5d80771d7d55ceb31f5961b7088b2e430cb5d","unresolved":false,"context_lines":[{"line_number":210,"context_line":"        exit_code \u003d manager.run()"},{"line_number":211,"context_line":"        return exit_code"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def stop(self):"},{"line_number":214,"context_line":"        # Cotyledon manages termination via ServiceWrapper. Additional logic"},{"line_number":215,"context_line":"        # can be added here if needed."},{"line_number":216,"context_line":"        pass"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    def wait(self):"},{"line_number":219,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":220,"context_line":"        # is required."},{"line_number":221,"context_line":"        pass"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"class Service(ServiceBase):"}],"source_content_type":"text/x-python","patch_set":6,"id":"d953231d_6216ad8e","line":221,"range":{"start_line":213,"start_character":0,"end_line":221,"end_character":12},"in_reply_to":"47e9af9b_3875521d","updated":"2025-04-23 14:49:49.000000000","message":"Done","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"6587cae53a2684c57617ef8617767866fa568bcd","unresolved":true,"context_lines":[{"line_number":210,"context_line":"        exit_code \u003d manager.run()"},{"line_number":211,"context_line":"        return exit_code"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def stop(self):"},{"line_number":214,"context_line":"        # Cotyledon manages termination via ServiceWrapper. Additional logic"},{"line_number":215,"context_line":"        # can be added here if needed."},{"line_number":216,"context_line":"        pass"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    def wait(self):"},{"line_number":219,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":220,"context_line":"        # is required."},{"line_number":221,"context_line":"        pass"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"class Service(ServiceBase):"}],"source_content_type":"text/x-python","patch_set":6,"id":"2a77c195_2d37300b","line":221,"range":{"start_line":213,"start_character":0,"end_line":221,"end_character":12},"in_reply_to":"54ded9e7_856b6089","updated":"2025-04-23 11:05:36.000000000","message":"Hi Hervé,\n\nThanks a lot for the question. The goal of this implementation is to keep the oslo.service API consistent and backend-agnostic.\n\nEven though Cotyledon handles the process lifecycle internally, we intentionally wrap it using classes like ServiceLauncher and ServiceWrapper to ensure feature parity and interface compatibility with the existing eventlet backend.\n\nThis allows oslo.service to expose a stable and unified API regardless of the chosen backend (eventlet/threading), which is critical for consumers expecting consistent behavior.\n\nAdditionally, this design gives us the flexibility to evolve or extend the backend’s internal behavior in the future without affecting the public API.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"6f7183c80d52c5ae6006c4f6eec0eda54780f810","unresolved":true,"context_lines":[{"line_number":19,"context_line":"import threading"},{"line_number":20,"context_line":"import traceback"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import cotyledon"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"from oslo_service._i18n import _"},{"line_number":25,"context_line":"from oslo_service import _options"}],"source_content_type":"text/x-python","patch_set":10,"id":"fbd5838f_09c64ae8","line":22,"updated":"2025-04-26 15:24:40.000000000","message":"This is missing from the requirements.txt. So simply pip installing this patch is not enough.\n\nThen I tried:\n```\npip install --upgrade -e \"../oslo.service[threading_backend]\"\n```\nBut that also did not installed this dep but warned:\n```\nWARNING: oslo-service 4.2.0.dev2 does not provide the extra \u0027threading-backend\u0027\n```","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":false,"context_lines":[{"line_number":19,"context_line":"import threading"},{"line_number":20,"context_line":"import traceback"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import cotyledon"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"from oslo_service._i18n import _"},{"line_number":25,"context_line":"from oslo_service import _options"}],"source_content_type":"text/x-python","patch_set":10,"id":"27cd7866_a2e5b404","line":22,"in_reply_to":"fbd5838f_09c64ae8","updated":"2025-05-06 14:16:25.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"9038d93da14332dafe07a9d1e450474f1d3b1b8b","unresolved":true,"context_lines":[{"line_number":78,"context_line":"        return sig_name in self._signals_by_name"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"class ServiceWrapper(cotyledon.Service):"},{"line_number":82,"context_line":"    \"\"\"A Cotyledon Service that wraps a Service instance."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    This class delegates the run/terminate calls to the underlying"}],"source_content_type":"text/x-python","patch_set":10,"id":"386dfae1_daae58e2","line":81,"updated":"2025-04-28 12:07:40.000000000","message":"When I try to use the threading backend with nova-scheduler, and with my local fixes for oslo.service top of this patch (see https://review.opendev.org/c/openstack/oslo.service/+/948310/2) Then I got the following traceback at service startup.\n```\nINFO oslo_service.backend.threading.service [None req-5e08bfe6-37c9-4db5-aa3b-c1590ef55510 None None] Launching service with 2 workers via Cotyledon\nProcess Process-1:\nTraceback (most recent call last):\n  File \"/usr/lib/python3.12/multiprocessing/process.py\", line 314, in _bootstrap\n    self.run()\n  File \"/usr/lib/python3.12/multiprocessing/process.py\", line 108, in run\n    self._target(*self._args, **self._kwargs)\n  File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_utils.py\", line 71, in _bootstrap_process\n    target(*args, **kwargs)\n  File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service.py\", line 162, in create_and_wait\n    sw \u003d cls(*args, **kwargs)\n         ^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service.py\", line 183, in __init__\n    self.service \u003d config.service(worker_id, *args, **kwargs)\n                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nTypeError: oslo_service.backend.threading.service.ServiceWrapper() argument after ** must be a mapping, not Service\nINFO cotyledon._service_manager [-] Child 104780 exited with status 1\n```","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":false,"context_lines":[{"line_number":78,"context_line":"        return sig_name in self._signals_by_name"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"class ServiceWrapper(cotyledon.Service):"},{"line_number":82,"context_line":"    \"\"\"A Cotyledon Service that wraps a Service instance."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    This class delegates the run/terminate calls to the underlying"}],"source_content_type":"text/x-python","patch_set":10,"id":"f7d11738_45446777","line":81,"in_reply_to":"386dfae1_daae58e2","updated":"2025-05-06 14:16:25.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"84e60631db86b2f35d1da620615e22b67e6f8016","unresolved":true,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"    def __init__(self, worker_id, conf, service_instance, **kwargs):"},{"line_number":89,"context_line":"        super().__init__(worker_id)"},{"line_number":90,"context_line":"        self.conf \u003d conf"},{"line_number":91,"context_line":"        if not isinstance(service_instance, ServiceBase):"},{"line_number":92,"context_line":"            raise TypeError(\"Service must be an instance of ServiceBase\")"},{"line_number":93,"context_line":"        self.service_instance \u003d service_instance"}],"source_content_type":"text/x-python","patch_set":10,"id":"aed21ec8_eef31ee0","line":90,"range":{"start_line":90,"start_character":7,"end_line":90,"end_character":24},"updated":"2025-04-28 12:34:03.000000000","message":"Should we not use the Cotyledon helper `oslo_config_glue`?\n\nhttps://github.com/sileht/cotyledon/blob/main/cotyledon/oslo_config_glue.py\n\nOctavia used it during their migration to handle config properly\nhttps://review.opendev.org/c/openstack/octavia/+/454873\n\nThis helper is also part of the migration guidance documented in Cotyledon:\nhttps://cotyledon.readthedocs.io/en/latest/oslo-service-migration.html","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fc599999f2140554d3d29dd361ec36a3e1b0f857","unresolved":false,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"    def __init__(self, worker_id, conf, service_instance, **kwargs):"},{"line_number":89,"context_line":"        super().__init__(worker_id)"},{"line_number":90,"context_line":"        self.conf \u003d conf"},{"line_number":91,"context_line":"        if not isinstance(service_instance, ServiceBase):"},{"line_number":92,"context_line":"            raise TypeError(\"Service must be an instance of ServiceBase\")"},{"line_number":93,"context_line":"        self.service_instance \u003d service_instance"}],"source_content_type":"text/x-python","patch_set":10,"id":"5d048984_5e00fb0c","line":90,"range":{"start_line":90,"start_character":7,"end_line":90,"end_character":24},"in_reply_to":"5c1d8a25_53bf368a","updated":"2025-05-13 10:36:38.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"fc411fe0e220bb8f9d5c497e0a5da1327c3e8e45","unresolved":true,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"    def __init__(self, worker_id, conf, service_instance, **kwargs):"},{"line_number":89,"context_line":"        super().__init__(worker_id)"},{"line_number":90,"context_line":"        self.conf \u003d conf"},{"line_number":91,"context_line":"        if not isinstance(service_instance, ServiceBase):"},{"line_number":92,"context_line":"            raise TypeError(\"Service must be an instance of ServiceBase\")"},{"line_number":93,"context_line":"        self.service_instance \u003d service_instance"}],"source_content_type":"text/x-python","patch_set":10,"id":"5c1d8a25_53bf368a","line":90,"range":{"start_line":90,"start_character":7,"end_line":90,"end_character":24},"in_reply_to":"aed21ec8_eef31ee0","updated":"2025-05-12 07:43:47.000000000","message":"I haven\u0027t had time yet to get back to the logging discrepancy I see in threading mode. (I.e. that oslo does not dump the loaded config to the logs at service startup in threading mode while it dumps it in eventlet mode). I guess this comment might be related so worth investigating. I will try to get to it this week...","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"ccdac048b569d24f83e0083f32d4fca9597309ac","unresolved":true,"context_lines":[{"line_number":129,"context_line":"        class CustomManager(cotyledon.ServiceManager):"},{"line_number":130,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":131,"context_line":"                super().__init__()"},{"line_number":132,"context_line":"                self.add(ServiceWrapper, workers, conf, service_instance)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":135,"context_line":"        exit_code \u003d manager.run()"}],"source_content_type":"text/x-python","patch_set":10,"id":"dba36d77_e3e65158","line":132,"updated":"2025-04-28 13:06:25.000000000","message":"I think this should be \n```python\n    self.add(ServiceWrapper, workers, args\u003d(conf, service_instance))\n```\n\notherwise the conf become args and service_instance become kwargs in the called code and that leads to `TypeError: oslo_service.backend.threading.service.ServiceWrapper() argument after ** must be a mapping, not Service\n` reported above","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":false,"context_lines":[{"line_number":129,"context_line":"        class CustomManager(cotyledon.ServiceManager):"},{"line_number":130,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":131,"context_line":"                super().__init__()"},{"line_number":132,"context_line":"                self.add(ServiceWrapper, workers, conf, service_instance)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":135,"context_line":"        exit_code \u003d manager.run()"}],"source_content_type":"text/x-python","patch_set":10,"id":"0d839c02_6de79c4f","line":132,"in_reply_to":"dba36d77_e3e65158","updated":"2025-05-06 14:16:25.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"a3a7baa277d74678014aead2cb49acf92e22b80b","unresolved":true,"context_lines":[{"line_number":153,"context_line":"    \"\"\""},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"    def __init__(self, threads\u003d1000):"},{"line_number":156,"context_line":"        self.tg \u003d threadgroup.ThreadGroup(threads)"},{"line_number":157,"context_line":"        self.backdoor_port \u003d None  # Optionally used for a backdoor interface."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    def reset(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"25eeb7d8_c203fcc6","line":156,"updated":"2025-04-28 11:51:48.000000000","message":"This call fails as the ThreadGroup does not take any argument in https://review.opendev.org/c/openstack/oslo.service/+/945720/10/oslo_service/backend/threading/threadgroup.py#72\n\n```\n(venv) stack@aio:/opt/stack/nova$ OS_NOVA_DISABLE_EVENTLET_PATCHING\u003dtrue nova-scheduler --config-file /etc/nova/nova.conf \nService is starting with native threading. This is currently experimental. Do not use it in production.\nCRITICAL nova [-] Unhandled error: TypeError: ThreadGroup.__init__() takes 1 positional argument but 2 were given\nERROR nova Traceback (most recent call last):\nERROR nova   File \"/opt/stack/data/venv/bin/nova-scheduler\", line 8, in \u003cmodule\u003e\nERROR nova     sys.exit(main())\nERROR nova              ^^^^^^\nERROR nova   File \"/opt/stack/nova/nova/cmd/scheduler.py\", line 45, in main\nERROR nova     server \u003d service.Service.create(\nERROR nova              ^^^^^^^^^^^^^^^^^^^^^^^\nERROR nova   File \"/opt/stack/nova/nova/service.py\", line 245, in create\nERROR nova     service_obj \u003d cls(host, binary, topic, manager,\nERROR nova                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nERROR nova   File \"/opt/stack/nova/nova/service.py\", line 101, in __init__\nERROR nova     super(Service, self).__init__()\nERROR nova   File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 156, in __init__\nERROR nova     self.tg \u003d threadgroup.ThreadGroup(threads)\nERROR nova               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nERROR nova TypeError: ThreadGroup.__init__() takes 1 positional argument but 2 were given\nERROR nova \n```","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":false,"context_lines":[{"line_number":153,"context_line":"    \"\"\""},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"    def __init__(self, threads\u003d1000):"},{"line_number":156,"context_line":"        self.tg \u003d threadgroup.ThreadGroup(threads)"},{"line_number":157,"context_line":"        self.backdoor_port \u003d None  # Optionally used for a backdoor interface."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    def reset(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"6290af6b_cfa60627","line":156,"in_reply_to":"25eeb7d8_c203fcc6","updated":"2025-05-06 14:16:25.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"ccdac048b569d24f83e0083f32d4fca9597309ac","unresolved":true,"context_lines":[{"line_number":265,"context_line":"        class CustomManager(cotyledon.ServiceManager):"},{"line_number":266,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":267,"context_line":"                super().__init__()"},{"line_number":268,"context_line":"                self.add(ServiceWrapper, workers, conf, service_instance)"},{"line_number":269,"context_line":""},{"line_number":270,"context_line":"        self._manager \u003d CustomManager("},{"line_number":271,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":10,"id":"014cb04f_d25448db","line":268,"updated":"2025-04-28 13:06:25.000000000","message":"ditto","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":false,"context_lines":[{"line_number":265,"context_line":"        class CustomManager(cotyledon.ServiceManager):"},{"line_number":266,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":267,"context_line":"                super().__init__()"},{"line_number":268,"context_line":"                self.add(ServiceWrapper, workers, conf, service_instance)"},{"line_number":269,"context_line":""},{"line_number":270,"context_line":"        self._manager \u003d CustomManager("},{"line_number":271,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":10,"id":"2dfd2368_0e3ef9ae","line":268,"in_reply_to":"014cb04f_d25448db","updated":"2025-05-06 14:16:25.000000000","message":"Done","commit_id":"4e861ff8fe4f037ec7594b564e6dbc66bd9d92cb"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"c8394537e7ca74cb77680c7e6dd8a84bcc57ae98","unresolved":true,"context_lines":[{"line_number":182,"context_line":"    For binaries running on hosts using a threading-based threadgroup."},{"line_number":183,"context_line":"    \"\"\""},{"line_number":184,"context_line":""},{"line_number":185,"context_line":"    def __init__(self, threads\u003d1000):"},{"line_number":186,"context_line":"        self.tg \u003d threadgroup.ThreadGroup(threads)"},{"line_number":187,"context_line":"        self.backdoor_port \u003d None  # Optionally used for a backdoor interface."},{"line_number":188,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"98db882b_f2d0b9ea","line":185,"updated":"2025-04-28 14:23:36.000000000","message":"it seems a `super().__init__()` is missing here causing the oslo.messaging server to not get fully initialized.\n```\nDEBUG nova.service [None req-1728fbe9-f2f6-40bc-9d94-ee4be5692949 None None] Creating RPC server for service scheduler {{(pid\u003d114719) start /opt/stack/nova/nova/service.py:177}}\nRPCServer.__init__ before super mro [\u003cclass \u0027oslo_messaging.rpc.server.RPCServer\u0027\u003e, \u003cclass \u0027oslo_messaging.server.MessageHandlingServer\u0027\u003e, \u003cclass \u0027oslo_service.backend.threading.service.Service\u0027\u003e, \u003cclass \u0027oslo_service.backend.base.ServiceBase\u0027\u003e, \u003cclass \u0027oslo_messaging.server._OrderedTaskRunner\u0027\u003e, \u003cclass \u0027object\u0027\u003e]\nMessageHandlingServer.__init__ before stuff\nMessageHandlingServer.__init__ before super\nMessageHandlingServer.__init__ after super\nRPCServer.__init__ after super\nTraceback (most recent call last):\n  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 97, in run\n    self.service_instance.start()\n  File \"/opt/stack/nova/nova/service.py\", line 190, in start\n    self.rpcserver.start()\n  File \"/opt/stack/oslo.messaging/oslo_messaging/server.py\", line 245, in wrapper\n    with self._reset_lock:\n         ^^^^^^^^^^^^^^^^\nAttributeError: \u0027RPCServer\u0027 object has no attribute \u0027_reset_lock\u0027\n```","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":false,"context_lines":[{"line_number":182,"context_line":"    For binaries running on hosts using a threading-based threadgroup."},{"line_number":183,"context_line":"    \"\"\""},{"line_number":184,"context_line":""},{"line_number":185,"context_line":"    def __init__(self, threads\u003d1000):"},{"line_number":186,"context_line":"        self.tg \u003d threadgroup.ThreadGroup(threads)"},{"line_number":187,"context_line":"        self.backdoor_port \u003d None  # Optionally used for a backdoor interface."},{"line_number":188,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"8b72ae51_37b8d55e","line":185,"in_reply_to":"98db882b_f2d0b9ea","updated":"2025-05-06 14:16:25.000000000","message":"Done","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"01b29c275bf9db7795cb71232232ab63508799d0","unresolved":true,"context_lines":[{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    def wait(self):"},{"line_number":207,"context_line":"        \"\"\"Wait for a service to shut down.\"\"\""},{"line_number":208,"context_line":"        self.tg.wait()"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":""},{"line_number":211,"context_line":"class Services:"}],"source_content_type":"text/x-python","patch_set":11,"id":"7b9c028a_3c4b2dad","line":208,"updated":"2025-04-28 14:29:13.000000000","message":"```\nTraceback (most recent call last):\n  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 98, in run\n    self.service_instance.wait()  # Block until the service stops.\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 209, in wait\n    self.tg.wait()\n    ^^^^^^^^^^^^\nAttributeError: \u0027ThreadGroup\u0027 object has no attribute \u0027wait\u0027\n```","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"7f63f50e8adbe7f6388b39abb8ab4f5d4d4f0a7c","unresolved":true,"context_lines":[{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    def wait(self):"},{"line_number":207,"context_line":"        \"\"\"Wait for a service to shut down.\"\"\""},{"line_number":208,"context_line":"        self.tg.wait()"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":""},{"line_number":211,"context_line":"class Services:"}],"source_content_type":"text/x-python","patch_set":11,"id":"c9e8c1c5_c9fd8e95","line":208,"in_reply_to":"7b9c028a_3c4b2dad","updated":"2025-04-28 14:38:36.000000000","message":"I locally changed this to waitall and that least to another issue in the threadgroup see there.","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fbcf7b6ec8a4baf0cce089a8516a5a469368338c","unresolved":false,"context_lines":[{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    def wait(self):"},{"line_number":207,"context_line":"        \"\"\"Wait for a service to shut down.\"\"\""},{"line_number":208,"context_line":"        self.tg.wait()"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":""},{"line_number":211,"context_line":"class Services:"}],"source_content_type":"text/x-python","patch_set":11,"id":"38d16ed9_c5a15193","line":208,"in_reply_to":"c9e8c1c5_c9fd8e95","updated":"2025-05-02 11:52:10.000000000","message":"Done","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1a0dfd8db466c20433b50be56c2a07248e5626cf","unresolved":true,"context_lines":[{"line_number":186,"context_line":"    def __init__(self, threads\u003d1000):"},{"line_number":187,"context_line":"        super().__init__()"},{"line_number":188,"context_line":""},{"line_number":189,"context_line":"        self.tg \u003d threadgroup.ThreadGroup()"},{"line_number":190,"context_line":"        self.backdoor_port \u003d None  # Optionally used for a backdoor interface."},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    def reset(self):"}],"source_content_type":"text/x-python","patch_set":16,"id":"3145944b_e71916d1","line":189,"updated":"2025-05-06 14:16:25.000000000","message":"you probably want to pass `threads` to the ThreadGroup()","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"b16edb5337ac70fcdd4c3f4a153d2247d25756c6","unresolved":false,"context_lines":[{"line_number":186,"context_line":"    def __init__(self, threads\u003d1000):"},{"line_number":187,"context_line":"        super().__init__()"},{"line_number":188,"context_line":""},{"line_number":189,"context_line":"        self.tg \u003d threadgroup.ThreadGroup()"},{"line_number":190,"context_line":"        self.backdoor_port \u003d None  # Optionally used for a backdoor interface."},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    def reset(self):"}],"source_content_type":"text/x-python","patch_set":16,"id":"3c748f3d_aee8048a","line":189,"in_reply_to":"3145944b_e71916d1","updated":"2025-05-07 11:42:13.000000000","message":"Done","commit_id":"51f82e20939bf5b4d11d99c2580027e93172da1b"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":36,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"class SignalHandler(metaclass\u003dSingleton):"},{"line_number":40,"context_line":"    \"\"\"SignalHandler that uses standard signal handling."},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    In this Cotyledon-based implementation, we rely on the default"}],"source_content_type":"text/x-python","patch_set":19,"id":"f7ece6f6_29d5e6c1","line":39,"range":{"start_line":39,"start_character":6,"end_line":39,"end_character":19},"updated":"2025-05-07 13:01:50.000000000","message":"IIUC the only difference between this and the one for eventlet backend is self.__setup_signal_interruption . Can\u0027t we create the common base class implementation with the others and create a child class for each backend ?","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"8150aeaaad45c47a2e9f2a56c0fe4170bb6766fe","unresolved":true,"context_lines":[{"line_number":36,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"class SignalHandler(metaclass\u003dSingleton):"},{"line_number":40,"context_line":"    \"\"\"SignalHandler that uses standard signal handling."},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    In this Cotyledon-based implementation, we rely on the default"}],"source_content_type":"text/x-python","patch_set":19,"id":"88eaf470_06477ac8","line":39,"range":{"start_line":39,"start_character":6,"end_line":39,"end_character":19},"in_reply_to":"d0358700_605d0d17","updated":"2025-05-15 07:54:30.000000000","message":"Also please make sure to actually use this class somewhere :)","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cfa8be8f4e0f89fb6fd6447565eab043420c9823","unresolved":true,"context_lines":[{"line_number":36,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"class SignalHandler(metaclass\u003dSingleton):"},{"line_number":40,"context_line":"    \"\"\"SignalHandler that uses standard signal handling."},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    In this Cotyledon-based implementation, we rely on the default"}],"source_content_type":"text/x-python","patch_set":19,"id":"d0358700_605d0d17","line":39,"range":{"start_line":39,"start_character":6,"end_line":39,"end_character":19},"in_reply_to":"f7ece6f6_29d5e6c1","updated":"2025-05-12 10:45:53.000000000","message":"Yes, you’re right, most of the logic is the same. I can absolutely factor out a base class and keep only the signal-specific parts in the backend-specific subclasses. I will do that in a follow-up patch to keep this one focused, if that works for you.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":113,"context_line":"    def launch_service(self, service, workers\u003d1):"},{"line_number":114,"context_line":"        _check_service_base(service)"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        if workers !\u003d 1:"},{"line_number":117,"context_line":"            raise NotImplementedError("},{"line_number":118,"context_line":"                \"Threading backend does not support multiple workers.\""},{"line_number":119,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"15f3785e_e986799a","line":116,"updated":"2025-05-07 13:01:50.000000000","message":"The existing Launcher class in eventlet accepts also None. Should we keep the same behavior ?\n\nAlso the error message is confusing because the existing launcher in eventlet does not support multiple workers, either.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cfa8be8f4e0f89fb6fd6447565eab043420c9823","unresolved":true,"context_lines":[{"line_number":113,"context_line":"    def launch_service(self, service, workers\u003d1):"},{"line_number":114,"context_line":"        _check_service_base(service)"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        if workers !\u003d 1:"},{"line_number":117,"context_line":"            raise NotImplementedError("},{"line_number":118,"context_line":"                \"Threading backend does not support multiple workers.\""},{"line_number":119,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"a213cec3_33dfbd34","line":116,"in_reply_to":"15f3785e_e986799a","updated":"2025-05-12 10:45:53.000000000","message":"Thanks a lot! Good point, you are right. I’ll align the behavior and update the message to make that clearer (and allow workers\u003dNone for consistency). Would it be OK to do that in a follow-up patch after this one is merged?","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"554413dac1e030ffed8329f002a0448a19ac04dc","unresolved":true,"context_lines":[{"line_number":113,"context_line":"    def launch_service(self, service, workers\u003d1):"},{"line_number":114,"context_line":"        _check_service_base(service)"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        if workers !\u003d 1:"},{"line_number":117,"context_line":"            raise NotImplementedError("},{"line_number":118,"context_line":"                \"Threading backend does not support multiple workers.\""},{"line_number":119,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"ae8916b2_269e998c","line":116,"in_reply_to":"a213cec3_33dfbd34","updated":"2025-05-12 11:59:14.000000000","message":"I have no strong disagreement with follow-up but I don\u0027t know the real benefit of it now given no -2 is kept in this review now.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cda2c142b19184f5b937c5fa6319696909da0c62","unresolved":false,"context_lines":[{"line_number":113,"context_line":"    def launch_service(self, service, workers\u003d1):"},{"line_number":114,"context_line":"        _check_service_base(service)"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        if workers !\u003d 1:"},{"line_number":117,"context_line":"            raise NotImplementedError("},{"line_number":118,"context_line":"                \"Threading backend does not support multiple workers.\""},{"line_number":119,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"a38cce32_bbfe8328","line":116,"in_reply_to":"ae8916b2_269e998c","updated":"2025-05-12 14:44:18.000000000","message":"Done","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":130,"context_line":"            self._launcher.stop()"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def restart(self):"},{"line_number":133,"context_line":"        raise NotImplementedError("},{"line_number":134,"context_line":"            \"Restart not supported in threading backend.\")"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"f2b6ef47_0fa3d274","line":133,"range":{"start_line":133,"start_character":14,"end_line":133,"end_character":33},"updated":"2025-05-07 13:01:50.000000000","message":"I wonder if we can just call stop and start here ?","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"554413dac1e030ffed8329f002a0448a19ac04dc","unresolved":true,"context_lines":[{"line_number":130,"context_line":"            self._launcher.stop()"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def restart(self):"},{"line_number":133,"context_line":"        raise NotImplementedError("},{"line_number":134,"context_line":"            \"Restart not supported in threading backend.\")"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"cf8e4aae_63b5e4bd","line":133,"range":{"start_line":133,"start_character":14,"end_line":133,"end_character":33},"in_reply_to":"9505d07f_57304aad","updated":"2025-05-12 11:59:14.000000000","message":"IMO we should not expose backend specific behavior to the interface and we should keep the compatibility as much as possible. For that sake we should consider implementing restart, which was my point.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"c8d12f9eb1048ad815e1da6bd71b450fe057c54f","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            self._launcher.stop()"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def restart(self):"},{"line_number":133,"context_line":"        raise NotImplementedError("},{"line_number":134,"context_line":"            \"Restart not supported in threading backend.\")"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"63c5df6d_46c7f2d7","line":133,"range":{"start_line":133,"start_character":14,"end_line":133,"end_character":33},"in_reply_to":"cf8e4aae_63b5e4bd","updated":"2025-05-12 14:56:54.000000000","message":"Done","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cfa8be8f4e0f89fb6fd6447565eab043420c9823","unresolved":true,"context_lines":[{"line_number":130,"context_line":"            self._launcher.stop()"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def restart(self):"},{"line_number":133,"context_line":"        raise NotImplementedError("},{"line_number":134,"context_line":"            \"Restart not supported in threading backend.\")"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9505d07f_57304aad","line":133,"range":{"start_line":133,"start_character":14,"end_line":133,"end_character":33},"in_reply_to":"f2b6ef47_0fa3d274","updated":"2025-05-12 10:45:53.000000000","message":"Yes, you’re right, I defined restart() explicitly to keep the same interface as the eventlet backend. That way, even if the method isn’t supported in the threading backend, consumers can rely on a consistent API across both implementations.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":277,"context_line":"            done.wait()"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":""},{"line_number":280,"context_line":"class ProcessLauncher:"},{"line_number":281,"context_line":"    \"\"\"A ProcessLauncher implementation."},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"       This implementation uses Cotyledon to manage multiple worker"}],"source_content_type":"text/x-python","patch_set":19,"id":"47769e31_d04b9317","line":280,"range":{"start_line":280,"start_character":6,"end_line":280,"end_character":21},"updated":"2025-05-07 13:01:50.000000000","message":"Is there any specific reason not to define this right after ServiceWrapper to make definition order consistent between these two files ?","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cfa8be8f4e0f89fb6fd6447565eab043420c9823","unresolved":true,"context_lines":[{"line_number":277,"context_line":"            done.wait()"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":""},{"line_number":280,"context_line":"class ProcessLauncher:"},{"line_number":281,"context_line":"    \"\"\"A ProcessLauncher implementation."},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"       This implementation uses Cotyledon to manage multiple worker"}],"source_content_type":"text/x-python","patch_set":19,"id":"3f2d8c2a_830d1b3c","line":280,"range":{"start_line":280,"start_character":6,"end_line":280,"end_character":21},"in_reply_to":"47769e31_d04b9317","updated":"2025-05-12 10:45:53.000000000","message":"Good catch, no strong reason, probably just a slip when I wrote the code. Happy to move it right after ServiceWrapper to keep things consistent. I can do it in a follow-up patch, unless you’d prefer it in this one.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"fc411fe0e220bb8f9d5c497e0a5da1327c3e8e45","unresolved":true,"context_lines":[{"line_number":307,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":308,"context_line":"                super().__init__()"},{"line_number":309,"context_line":"                self.add("},{"line_number":310,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self._manager \u003d CustomManager("},{"line_number":313,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":20,"id":"39e45934_d1e8d831","line":310,"updated":"2025-05-12 07:43:47.000000000","message":"Re trying os.spawn instead of os.fork: We are passing here a bunch of things to the new Process. That gets serialized (pickled) by multiprocessing.Process.start() as parameters to the new Process. There are things that cannot be pickled. The first thing I reported couple days ago is a lambda as a default arg in oslo.config[1]. I replaced that with a module level function. Just to see that there are other things like:\n* oslo.config.ConfigOpts._oparser which is argparse.ArgumentParser which has a local func def in `__init__` that seems to be a problem. I hacked this out just to see further by resetting the CONF._oparser value to None before spawn. \n* _thread.RLock. I haven\u0027t found the exact source of it but I guess we use it in many places. \n\nI have to conclude that for us it is not easy to switch to os.spawn. So even when python switches to it by default in 3.14 we need to use multiprocessing.set_start_method to use os.fork to keep our services working. And in the future when python drops the support of os.fork we have to remove the ability to create worker processes and delegate to the higher level deployment tool (e.g. k8s) to scale the service to multiple processes.\n\n```\nMay 11 17:44:54 aio nova-scheduler[101791]: INFO oslo_service.backend.threading.service [None req-ed8455c3-5dad-4f66-b498-42924b889b17 None None] Launching service with 2 workers via Cotyledon\nMay 11 17:44:54 aio nova-scheduler[101791]: Exception in thread Thread-7 (_child_supervisor_thread):\nMay 11 17:44:54 aio nova-scheduler[101791]: Traceback (most recent call last):\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/threading.py\", line 1073, in _bootstrap_inner\nMay 11 17:44:54 aio nova-scheduler[101791]:     self.run()\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/threading.py\", line 1010, in run\nMay 11 17:44:54 aio nova-scheduler[101791]:     self._target(*self._args, **self._kwargs)\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service_manager.py\", line 256, in _child_supervisor_thread\nMay 11 17:44:54 aio nova-scheduler[101791]:     self._adjust_workers()\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service_manager.py\", line 343, in _adjust_workers\nMay 11 17:44:54 aio nova-scheduler[101791]:     self._start_worker(service_id, worker_id)\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service_manager.py\", line 414, in _start_worker\nMay 11 17:44:54 aio nova-scheduler[101791]:     p \u003d _utils.spawn_process(\nMay 11 17:44:54 aio nova-scheduler[101791]:         ^^^^^^^^^^^^^^^^^^^^^\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_utils.py\", line 80, in spawn_process\nMay 11 17:44:54 aio nova-scheduler[101791]:     p.start()\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/process.py\", line 121, in start\nMay 11 17:44:54 aio nova-scheduler[101791]:     self._popen \u003d self._Popen(self)\nMay 11 17:44:54 aio nova-scheduler[101791]:                   ^^^^^^^^^^^^^^^^^\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/context.py\", line 224, in _Popen\nMay 11 17:44:54 aio nova-scheduler[101791]:     return _default_context.get_context().Process._Popen(process_obj)\nMay 11 17:44:54 aio nova-scheduler[101791]:            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/context.py\", line 289, in _Popen\nMay 11 17:44:54 aio nova-scheduler[101791]:     return Popen(process_obj)\nMay 11 17:44:54 aio nova-scheduler[101791]:            ^^^^^^^^^^^^^^^^^^\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/popen_spawn_posix.py\", line 32, in __init__\nMay 11 17:44:54 aio nova-scheduler[101791]:     super().__init__(process_obj)\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/popen_fork.py\", line 19, in __init__\nMay 11 17:44:54 aio nova-scheduler[101791]:     self._launch(process_obj)\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/popen_spawn_posix.py\", line 47, in _launch\nMay 11 17:44:54 aio nova-scheduler[101791]:     reduction.dump(process_obj, fp)\nMay 11 17:44:54 aio nova-scheduler[101791]:   File \"/usr/lib/python3.12/multiprocessing/reduction.py\", line 60, in dump\nMay 11 17:44:54 aio nova-scheduler[101791]:     ForkingPickler(file, protocol).dump(obj)\nMay 11 17:44:54 aio nova-scheduler[101791]: TypeError: cannot pickle \u0027_thread.RLock\u0027 object\n```\n\n\n[1]https://github.com/openstack/oslo.config/blob/b18ff43e63916849adbd6a46f42744f4491b873e/oslo_config/cfg.py#L1387\n[2]https://github.com/python/cpython/blob/0eb448cae5e9008f815204d8b46bfd7cd641a152/Lib/argparse.py#L1911-L1914","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"249c9ba5ce6029d2064ce29aee42e2706d66ab19","unresolved":true,"context_lines":[{"line_number":307,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":308,"context_line":"                super().__init__()"},{"line_number":309,"context_line":"                self.add("},{"line_number":310,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self._manager \u003d CustomManager("},{"line_number":313,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":20,"id":"3f97914a_8fb44fc6","line":310,"in_reply_to":"39e45934_d1e8d831","updated":"2025-05-12 10:24:19.000000000","message":"Thanks a lot for digging into it, really appreciate the details. \n\nSo we stay on the same page: fork() is still the only reliable path for us today, and in the long run we will probably need to offload scaling to something like K8s anyway.\nGood to know we’ve hit the same limits!","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"98d50a01b6923bed120c00730908b0fa3db81ade","unresolved":true,"context_lines":[{"line_number":307,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":308,"context_line":"                super().__init__()"},{"line_number":309,"context_line":"                self.add("},{"line_number":310,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self._manager \u003d CustomManager("},{"line_number":313,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":20,"id":"e6d17b40_f020d5fa","line":310,"in_reply_to":"3f97914a_8fb44fc6","updated":"2026-01-06 21:30:08.000000000","message":"I was also trying why we do not use spawn instwad of fork and then came across to this comment. Thanks for adding details about this limitation of spawn does not work in our case.\n\nI think this is good info to add somewhere with the details gibi added here. I know you added it in releasenotes with high level statemnt but it will be good to add this in code or documentation so that we will eaisly know why multiprocessing spawn method is not used via cotyledon and when multiprocessing switch to spawn by default then that will break our service launch logic.","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"17188fbf58f8f07906103c989ebd3fbd7b0257d8","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":308,"context_line":"                super().__init__()"},{"line_number":309,"context_line":"                self.add("},{"line_number":310,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self._manager \u003d CustomManager("},{"line_number":313,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":20,"id":"a118477f_c975c0bd","line":310,"in_reply_to":"7845d892_0a43e7e9","updated":"2026-01-21 18:32:17.000000000","message":"I have not test that yet but I agree that long term solution is spawn. I think we should not have the pickle issue in forksever but yes we need to test. I am concern about forkserver being default in python 3.13 but fork is not going to be removed soon (hope we will be ready with spawn by then).","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"9d511ac3e32cb00faa0f1a43c285ace2d77bc0bb","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":308,"context_line":"                super().__init__()"},{"line_number":309,"context_line":"                self.add("},{"line_number":310,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self._manager \u003d CustomManager("},{"line_number":313,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":20,"id":"7845d892_0a43e7e9","line":310,"in_reply_to":"939bff0e_7f5ebe0b","updated":"2026-01-14 14:45:32.000000000","message":"forkserver is interesting. I haven\u0027t tried it yet but I foresee the following situation. It is safe as it forks from a clean state. It is fast as it does not spawn a new process but duplicate a safe state of the main process memory. But this means we still cannot easily pass data to the forked worker process but need to rely on pickling like in case of spawn so we hit the not-everything-can-be-pickled issue. Btw I think pure fork sidestep the pickle problem by not trying to send data to the fork but relying on the fact that the child got the copy of the parents memory so that copy has all the data the child needs.\n\nbottom line I agree to try, but I have no high hopes for forkserver to be a direct solution to our problem.","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"271fd09203418387d5f4bef5908a0ff8bfaa67a8","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":308,"context_line":"                super().__init__()"},{"line_number":309,"context_line":"                self.add("},{"line_number":310,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self._manager \u003d CustomManager("},{"line_number":313,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":20,"id":"939bff0e_7f5ebe0b","line":310,"in_reply_to":"e6d17b40_f020d5fa","updated":"2026-01-08 20:46:43.000000000","message":"I opened a bug to know this limitation and for tracking https://bugs.launchpad.net/oslo.service/+bug/2137597\n\nAfter looking into the multiprocessing doc, \u0027spawn\u0027 is not default in python3.14, it seems that \u0027forkserver\u0027 become the default method. \u0027forkservre\u0027 still use fork but in safe way that it does not create any issue on process with multithreaded (our use case).\n\n-----------------------\nforkserver\n    When the program starts and selects the forkserver start method, a server process is spawned. From then on, whenever a new process is needed, the parent process connects to the server and requests that it fork a new process. The fork server process is single threaded unless system libraries or preloaded imports spawn threads as a side-effect so it is generally safe for it to use os.fork(). No unnecessary resources are inherited.\n\nAvailable on POSIX platforms which support passing file descriptors over Unix pipes such as Linux. The default on those.\n\nChanged in version 3.14: This became the default start method on POSIX platforms.\n\n-------------------------\n\n- https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods\n\nI think we should give \u0027forkserver\u0027 a try/test for process with multithread.","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b478c6faf57ce12eb91d31b69a36e67608ac7be","unresolved":true,"context_lines":[{"line_number":95,"context_line":"    def run(self):"},{"line_number":96,"context_line":"        try:"},{"line_number":97,"context_line":"            self.service_instance.start()"},{"line_number":98,"context_line":"            self.service_instance.wait()  # Block until the service stops."},{"line_number":99,"context_line":"        except Exception:"},{"line_number":100,"context_line":"            traceback.print_exc()"},{"line_number":101,"context_line":"            sys.exit(1)"}],"source_content_type":"text/x-python","patch_set":22,"id":"eb00d8eb_b613c23c","line":98,"updated":"2025-05-12 12:09:04.000000000","message":"This stops the periodics looping call at service startup.","commit_id":"8872bdab52e8d842795c8834eceb5241a4cb8c7e"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"98d50a01b6923bed120c00730908b0fa3db81ade","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    def run(self):"},{"line_number":96,"context_line":"        try:"},{"line_number":97,"context_line":"            self.service_instance.start()"},{"line_number":98,"context_line":"            self.service_instance.wait()  # Block until the service stops."},{"line_number":99,"context_line":"        except Exception:"},{"line_number":100,"context_line":"            traceback.print_exc()"},{"line_number":101,"context_line":"            sys.exit(1)"}],"source_content_type":"text/x-python","patch_set":22,"id":"14663ca1_15f33013","line":98,"in_reply_to":"a9b87ce8_b21da29a","updated":"2026-01-06 21:30:08.000000000","message":"I posted this comment in wrong place","commit_id":"8872bdab52e8d842795c8834eceb5241a4cb8c7e"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"eb02a62eedbdd28e2ee0aa1be808eb54b38e0a8a","unresolved":true,"context_lines":[{"line_number":95,"context_line":"    def run(self):"},{"line_number":96,"context_line":"        try:"},{"line_number":97,"context_line":"            self.service_instance.start()"},{"line_number":98,"context_line":"            self.service_instance.wait()  # Block until the service stops."},{"line_number":99,"context_line":"        except Exception:"},{"line_number":100,"context_line":"            traceback.print_exc()"},{"line_number":101,"context_line":"            sys.exit(1)"}],"source_content_type":"text/x-python","patch_set":22,"id":"a9b87ce8_b21da29a","line":98,"in_reply_to":"eb00d8eb_b613c23c","updated":"2026-01-06 21:06:54.000000000","message":"I was also trying why we do not use spawn instwad of fork and then came across to this comment. Thanks for adding details about this limitation of spawn does not work in our case. \n\nI think this is good info to add somewhere with the details gibi added here. I know you added it in releasenotes with high level statemnt but it will be good to add this in code or documentation so that we will eaisly know why multiprocessing spawn method is not used via cotyledon and when multiprocessing switch to spawn by default then that will break our service launch logic.","commit_id":"8872bdab52e8d842795c8834eceb5241a4cb8c7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":116,"context_line":"        if workers not in (None, 1):"},{"line_number":117,"context_line":"            raise NotImplementedError(\"Multiple workers is not supported.\")"},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"        self._launcher \u003d service"},{"line_number":120,"context_line":"        service.start()"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"        return service"}],"source_content_type":"text/x-python","patch_set":26,"id":"7169b3d4_196b3204","line":119,"updated":"2025-05-13 10:39:42.000000000","message":"nit: it\u0027s odd to call a service \"launcher\" in this context","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"8d4d8203e9957e5ef5d48e456eb24902dc303821","unresolved":true,"context_lines":[{"line_number":121,"context_line":""},{"line_number":122,"context_line":"        return service"},{"line_number":123,"context_line":""},{"line_number":124,"context_line":"    def wait(self):"},{"line_number":125,"context_line":"        if self._launcher:"},{"line_number":126,"context_line":"            self._launcher.wait()"},{"line_number":127,"context_line":""}],"source_content_type":"text/x-python","patch_set":26,"id":"ae47d8cb_2e5ef680","line":124,"updated":"2025-05-13 10:47:44.000000000","message":"The eventlet counterpart has systemd and signal logic. This is a significant omission.","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"2a4485a69166c259d9d498cd132ef1ff8f4d7452","unresolved":true,"context_lines":[{"line_number":161,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":162,"context_line":"                super().__init__()"},{"line_number":163,"context_line":"                self.add("},{"line_number":164,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":167,"context_line":"        exit_code \u003d manager.run()"}],"source_content_type":"text/x-python","patch_set":26,"id":"91c09be0_bef262f9","line":164,"updated":"2025-05-12 16:57:43.000000000","message":"nit: is it any different from creating a ServiceManager() then calling add() on it?","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"ed82635151179a3f021a542119339ed54589f890","unresolved":false,"context_lines":[{"line_number":161,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":162,"context_line":"                super().__init__()"},{"line_number":163,"context_line":"                self.add("},{"line_number":164,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":167,"context_line":"        exit_code \u003d manager.run()"}],"source_content_type":"text/x-python","patch_set":26,"id":"e4bb9be2_6d9fd442","line":164,"in_reply_to":"91c09be0_bef262f9","updated":"2025-05-12 23:35:33.000000000","message":"Done","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":161,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":162,"context_line":"                super().__init__()"},{"line_number":163,"context_line":"                self.add("},{"line_number":164,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":167,"context_line":"        exit_code \u003d manager.run()"}],"source_content_type":"text/x-python","patch_set":26,"id":"86e0306f_b377411b","line":164,"in_reply_to":"e4bb9be2_6d9fd442","updated":"2025-05-13 10:39:42.000000000","message":"Has anything been changed?","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"2a4485a69166c259d9d498cd132ef1ff8f4d7452","unresolved":true,"context_lines":[{"line_number":164,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":167,"context_line":"        exit_code \u003d manager.run()"},{"line_number":168,"context_line":"        return exit_code"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def stop(self):"}],"source_content_type":"text/x-python","patch_set":26,"id":"1bc9d175_9fb4231a","line":167,"updated":"2025-05-12 16:57:43.000000000","message":"Won\u0027t this wait until the service is done before returning, effectively preventing launch_service from being called several times (like we do in Ironic)?","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"ed82635151179a3f021a542119339ed54589f890","unresolved":false,"context_lines":[{"line_number":164,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":167,"context_line":"        exit_code \u003d manager.run()"},{"line_number":168,"context_line":"        return exit_code"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def stop(self):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3ccd9abe_6298dcb4","line":167,"in_reply_to":"1bc9d175_9fb4231a","updated":"2025-05-12 23:35:33.000000000","message":"Done","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":164,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"        manager \u003d CustomManager(self.conf, workers, service_instance)"},{"line_number":167,"context_line":"        exit_code \u003d manager.run()"},{"line_number":168,"context_line":"        return exit_code"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def stop(self):"}],"source_content_type":"text/x-python","patch_set":26,"id":"bc91c1b0_13d1f910","line":167,"in_reply_to":"3ccd9abe_6298dcb4","updated":"2025-05-13 10:39:42.000000000","message":"Not addressed yet? I\u0027m okay with merging the current version, but Ironic won\u0027t be able to migrate to it (JFYI).","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"2a4485a69166c259d9d498cd132ef1ff8f4d7452","unresolved":true,"context_lines":[{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    def wait(self):"},{"line_number":176,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":177,"context_line":"        # is required."},{"line_number":178,"context_line":"        pass"},{"line_number":179,"context_line":""},{"line_number":180,"context_line":""}],"source_content_type":"text/x-python","patch_set":26,"id":"a8a40420_5b35e983","line":177,"updated":"2025-05-12 16:57:43.000000000","message":"This is a severe API break from the eventlet backend.","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"ed82635151179a3f021a542119339ed54589f890","unresolved":false,"context_lines":[{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    def wait(self):"},{"line_number":176,"context_line":"        # Cotyledon blocks inside manager.run(). No additional wait logic"},{"line_number":177,"context_line":"        # is required."},{"line_number":178,"context_line":"        pass"},{"line_number":179,"context_line":""},{"line_number":180,"context_line":""}],"source_content_type":"text/x-python","patch_set":26,"id":"f6cf12c8_d1f7759c","line":177,"in_reply_to":"a8a40420_5b35e983","updated":"2025-05-12 23:35:33.000000000","message":"Done","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":215,"context_line":"class Services:"},{"line_number":216,"context_line":"    \"\"\"Manages multiple services running in threads."},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"    This class is used by the launcher to start, stop, and restart"},{"line_number":219,"context_line":"    services."},{"line_number":220,"context_line":"    \"\"\""},{"line_number":221,"context_line":""}],"source_content_type":"text/x-python","patch_set":26,"id":"2269583a_1a40bc2f","line":218,"updated":"2025-05-13 10:39:42.000000000","message":"nit: is it though? I don\u0027t immediately see any references to this class anywhere.\n\nThis class could be usable for Ironic where we need to run several services under one launcher. But for that, it needs to inherit ServiceBase and provide a start()","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":221,"context_line":""},{"line_number":222,"context_line":"    def __init__(self, restart_method\u003d\u0027reload\u0027):"},{"line_number":223,"context_line":"        if restart_method not in _LAUNCHER_RESTART_METHODS:"},{"line_number":224,"context_line":"            raise ValueError(_(\"Invalid restart_method: %s\") % restart_method)"},{"line_number":225,"context_line":"        self.restart_method \u003d restart_method"},{"line_number":226,"context_line":"        self.services \u003d []"},{"line_number":227,"context_line":"        self.tg \u003d threadgroup.ThreadGroup()"}],"source_content_type":"text/x-python","patch_set":26,"id":"1a7734ec_1168f452","line":224,"updated":"2025-05-13 10:39:42.000000000","message":"nit: this is the only message that is translated in this file","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":224,"context_line":"            raise ValueError(_(\"Invalid restart_method: %s\") % restart_method)"},{"line_number":225,"context_line":"        self.restart_method \u003d restart_method"},{"line_number":226,"context_line":"        self.services \u003d []"},{"line_number":227,"context_line":"        self.tg \u003d threadgroup.ThreadGroup()"},{"line_number":228,"context_line":"        self.done \u003d threading.Event()"},{"line_number":229,"context_line":""},{"line_number":230,"context_line":"    def add(self, service):"}],"source_content_type":"text/x-python","patch_set":26,"id":"b22a8a34_3be36652","line":227,"updated":"2025-05-13 10:39:42.000000000","message":"nit: customizable number of threads","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":256,"context_line":"            self.done \u003d threading.Event()"},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"        for restart_service in self.services:"},{"line_number":259,"context_line":"            restart_service.reset()"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"            if self.restart_method \u003d\u003d \u0027reload\u0027:"},{"line_number":262,"context_line":"                self.tg.add_thread("}],"source_content_type":"text/x-python","patch_set":26,"id":"ccd0c845_96d22042","line":259,"updated":"2025-05-13 10:39:42.000000000","message":"nit: you may end up calling reset() on a stopped service","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":283,"context_line":""},{"line_number":284,"context_line":"       This implementation uses Cotyledon to manage multiple worker"},{"line_number":285,"context_line":"       processes. If no_fork\u003dTrue, the service runs in the master process"},{"line_number":286,"context_line":"       directly without forking."},{"line_number":287,"context_line":"    \"\"\""},{"line_number":288,"context_line":""},{"line_number":289,"context_line":"    def __init__(self, conf, restart_method\u003d\u0027reload\u0027, no_fork\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":26,"id":"e1c8f9fa_d42c9740","line":286,"updated":"2025-05-13 10:39:42.000000000","message":"I\u0027m really puzzled by no_fork but I guess you have a use case for that? I\u0027d be more clear about it since it looks like something very niche.","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":308,"context_line":"            def __init__(self, conf, workers, service_instance):"},{"line_number":309,"context_line":"                super().__init__()"},{"line_number":310,"context_line":"                self.add("},{"line_number":311,"context_line":"                    ServiceWrapper, workers, args\u003d(conf, service_instance))"},{"line_number":312,"context_line":""},{"line_number":313,"context_line":"        self._manager \u003d CustomManager("},{"line_number":314,"context_line":"            self.conf, workers, self._service_instance)"}],"source_content_type":"text/x-python","patch_set":26,"id":"4ecb792a_19804245","line":311,"updated":"2025-05-13 10:39:42.000000000","message":"Same comment on unnecessary subclassing","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":319,"context_line":""},{"line_number":320,"context_line":"    def wait(self):"},{"line_number":321,"context_line":"        if self.no_fork:"},{"line_number":322,"context_line":"            return 0"},{"line_number":323,"context_line":"        return self._exit_code"},{"line_number":324,"context_line":""},{"line_number":325,"context_line":"    def stop(self):"}],"source_content_type":"text/x-python","patch_set":26,"id":"abdf2a7c_a6815517","line":322,"updated":"2025-05-13 10:39:42.000000000","message":"nit: undocumented return value","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":325,"context_line":"    def stop(self):"},{"line_number":326,"context_line":"        LOG.info(\"Stopping service\")"},{"line_number":327,"context_line":"        if self._manager:"},{"line_number":328,"context_line":"            self._manager._terminate(None, None)"},{"line_number":329,"context_line":""},{"line_number":330,"context_line":""},{"line_number":331,"context_line":"def launch(conf, service, workers\u003d1, restart_method\u003d\u0027reload\u0027, no_fork\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":26,"id":"033847b2_2719da21","line":328,"updated":"2025-05-13 10:39:42.000000000","message":"You\u0027re calling a private function of a 3rd party class, this seems risky","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":343,"context_line":"    if workers is not None and workers \u003c\u003d 0:"},{"line_number":344,"context_line":"        raise ValueError(\"Number of workers should be positive!\")"},{"line_number":345,"context_line":""},{"line_number":346,"context_line":"    if workers \u003d\u003d 1 and not no_fork:"},{"line_number":347,"context_line":"        launcher \u003d ServiceLauncher(conf, restart_method\u003drestart_method)"},{"line_number":348,"context_line":"    else:"},{"line_number":349,"context_line":"        launcher \u003d ProcessLauncher("}],"source_content_type":"text/x-python","patch_set":26,"id":"73e59d2a_4d33fc38","line":346,"updated":"2025-05-13 10:39:42.000000000","message":"This is a very confusing logic, and it should at least be thoroughly documented. There is nothing in passing workers\u003d4 that implies not using threads.","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":35,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"class SignalHandler(metaclass\u003dSingleton):"},{"line_number":39,"context_line":"    def __init__(self, *args, **kwargs):"},{"line_number":40,"context_line":"        super().__init__(*args, **kwargs)"},{"line_number":41,"context_line":"        self._signals_by_name, self.signals_to_name \u003d get_signal_mappings()"}],"source_content_type":"text/x-python","patch_set":29,"id":"50d3d654_83d30dc3","line":38,"updated":"2025-05-13 11:44:01.000000000","message":"This class seems unused - see below","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":101,"context_line":"        service.start()"},{"line_number":102,"context_line":"        return service"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    def wait(self):"},{"line_number":105,"context_line":"        if self._launcher:"},{"line_number":106,"context_line":"            self._launcher.wait()"},{"line_number":107,"context_line":""}],"source_content_type":"text/x-python","patch_set":29,"id":"80e8ba05_08648370","line":104,"updated":"2025-05-13 11:44:01.000000000","message":"Missing systemd and signal logic here and in ServiceLauncher","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":119,"context_line":"    def __init__(self, conf, restart_method\u003d\u0027reload\u0027):"},{"line_number":120,"context_line":"        self.conf \u003d conf"},{"line_number":121,"context_line":"        self.restart_method \u003d restart_method"},{"line_number":122,"context_line":"        self.backdoor_port \u003d None"},{"line_number":123,"context_line":"        self._manager \u003d cotyledon.ServiceManager()"},{"line_number":124,"context_line":"        conf.register_opts(_options.service_opts)"},{"line_number":125,"context_line":"        oslo_config_glue.setup(conf, self._manager)"}],"source_content_type":"text/x-python","patch_set":29,"id":"32ae822e_f519c158","line":122,"updated":"2025-05-13 11:44:01.000000000","message":"Wasn\u0027t backdoor an eventlet-specific feature?","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":165,"context_line":"        self.tg.waitall()"},{"line_number":166,"context_line":""},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"class Services:"},{"line_number":169,"context_line":"    def __init__(self, restart_method\u003d\u0027reload\u0027):"},{"line_number":170,"context_line":"        if restart_method not in _LAUNCHER_RESTART_METHODS:"},{"line_number":171,"context_line":"            raise ValueError(_(\"Invalid restart_method: %s\") % restart_method)"}],"source_content_type":"text/x-python","patch_set":29,"id":"f3c9fe9c_60dc921d","line":168,"updated":"2025-05-13 11:44:01.000000000","message":"This class still seems unused","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":196,"context_line":"            self.done \u003d threading.Event()"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        for restart_service in self.services:"},{"line_number":199,"context_line":"            restart_service.reset()"},{"line_number":200,"context_line":"            if self.restart_method \u003d\u003d \u0027reload\u0027:"},{"line_number":201,"context_line":"                self.tg.add_thread("},{"line_number":202,"context_line":"                    self.run_service, restart_service, self.done)"}],"source_content_type":"text/x-python","patch_set":29,"id":"d2d60980_396d001c","line":199,"updated":"2025-05-13 11:44:01.000000000","message":"nit: potentially calling reset on a stopped service","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":231,"context_line":"            service.wait()"},{"line_number":232,"context_line":"            return"},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"        self._manager \u003d cotyledon.ServiceManager()"},{"line_number":235,"context_line":"        oslo_config_glue.setup(self.conf, self._manager)"},{"line_number":236,"context_line":"        self._manager.add(ServiceWrapper, workers,"},{"line_number":237,"context_line":"                          args\u003d(self._service_instance,))"}],"source_content_type":"text/x-python","patch_set":29,"id":"dc49e861_7cef1f68","line":234,"updated":"2025-05-13 11:44:01.000000000","message":"launch_service can be called more than once, this logic will overwrite the previously created manager","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"d15fc1c2d1d1f3c9f6578319a2a5f63daa7c45c1","unresolved":true,"context_lines":[{"line_number":231,"context_line":"            service.wait()"},{"line_number":232,"context_line":"            return"},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"        self._manager \u003d cotyledon.ServiceManager()"},{"line_number":235,"context_line":"        oslo_config_glue.setup(self.conf, self._manager)"},{"line_number":236,"context_line":"        self._manager.add(ServiceWrapper, workers,"},{"line_number":237,"context_line":"                          args\u003d(self._service_instance,))"}],"source_content_type":"text/x-python","patch_set":29,"id":"27f5b1b4_f8aecd43","line":234,"in_reply_to":"dc49e861_7cef1f68","updated":"2025-05-14 10:30:38.000000000","message":"I agree with Dimitry, I think the service manager should be a singleton, or should tend towards that.","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"c84f26c1d7c59129a455055949b8eb84535eb3aa","unresolved":true,"context_lines":[{"line_number":253,"context_line":"    if workers is not None and workers \u003c\u003d 0:"},{"line_number":254,"context_line":"        raise ValueError(\"Number of workers should be positive!\")"},{"line_number":255,"context_line":""},{"line_number":256,"context_line":"    if workers \u003d\u003d 1 and not no_fork:"},{"line_number":257,"context_line":"        launcher \u003d ServiceLauncher(conf, restart_method\u003drestart_method)"},{"line_number":258,"context_line":"    else:"},{"line_number":259,"context_line":"        launcher \u003d ProcessLauncher("}],"source_content_type":"text/x-python","patch_set":29,"id":"ce6b1a19_ae871cab","line":256,"updated":"2025-05-13 11:44:01.000000000","message":"See previous patchsets, this is a real footgun, especially since ServiceLauncher actually supports workers\u003e1","commit_id":"adfda80ca5de2bf19103677375af731b6a7f9a73"}],"oslo_service/backend/threading/threadgroup.py":[{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"6e15284837ddcb28171d830f61e3ca3f5f64c03f","unresolved":true,"context_lines":[{"line_number":46,"context_line":"    def wait(self):"},{"line_number":47,"context_line":"        self.thread.join()"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"    def link(self, func, *args, **kwargs):"},{"line_number":50,"context_line":"        # Optionally schedule a callback after thread completion."},{"line_number":51,"context_line":"        pass"},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"    def cancel(self, *throw_args):"},{"line_number":54,"context_line":"        # Optionally implement cancellation if required."},{"line_number":55,"context_line":"        pass"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"# --- End of new Thread wrapper ---"},{"line_number":58,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"e16ab478_d1363f7f","line":55,"range":{"start_line":49,"start_character":0,"end_line":55,"end_character":12},"updated":"2025-04-22 14:40:11.000000000","message":"This class do not seems to be an abstract class, I\u0027m not sure to see the needs of having these empty methods.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"20ce4c236c18afb03d1a973abb7347644d0fd1da","unresolved":false,"context_lines":[{"line_number":46,"context_line":"    def wait(self):"},{"line_number":47,"context_line":"        self.thread.join()"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"    def link(self, func, *args, **kwargs):"},{"line_number":50,"context_line":"        # Optionally schedule a callback after thread completion."},{"line_number":51,"context_line":"        pass"},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"    def cancel(self, *throw_args):"},{"line_number":54,"context_line":"        # Optionally implement cancellation if required."},{"line_number":55,"context_line":"        pass"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"# --- End of new Thread wrapper ---"},{"line_number":58,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"364b9e87_7755653b","line":55,"range":{"start_line":49,"start_character":0,"end_line":55,"end_character":12},"in_reply_to":"71bd9a55_5451690c","updated":"2025-04-23 14:48:22.000000000","message":"Done","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"6587cae53a2684c57617ef8617767866fa568bcd","unresolved":true,"context_lines":[{"line_number":46,"context_line":"    def wait(self):"},{"line_number":47,"context_line":"        self.thread.join()"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"    def link(self, func, *args, **kwargs):"},{"line_number":50,"context_line":"        # Optionally schedule a callback after thread completion."},{"line_number":51,"context_line":"        pass"},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"    def cancel(self, *throw_args):"},{"line_number":54,"context_line":"        # Optionally implement cancellation if required."},{"line_number":55,"context_line":"        pass"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"# --- End of new Thread wrapper ---"},{"line_number":58,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"71bd9a55_5451690c","line":55,"range":{"start_line":49,"start_character":0,"end_line":55,"end_character":12},"in_reply_to":"e16ab478_d1363f7f","updated":"2025-04-23 11:05:36.000000000","message":"Thanks a lot for your comment — you’re totally right, the class isn’t abstract, and those methods (stop, link, cancel) are basically no-ops in this implementation.\n\nBut the idea behind it is to keep the interface aligned with the eventlet backend. It’s mostly about preserving compatibility for oslo.service users, so they don’t have to care about which backend is actually running underneath.\n\nIn the threading world, we obviously can’t kill() or cancel() a thread the way eventlet can. But by keeping those methods in place (and documenting them clearly as no-ops), we make sure the API stays consistent and backend-agnostic — which is one of the main goals of this patch.\n\nLet me know if you’d prefer a different approach, like raising NotImplementedError, but for now I think the no-op version keeps things smoother for downstream projects.\n\nThanks a lot again for the review.","commit_id":"65ccd17e69d80fc18b6e7da56b97bc04d9c400c1"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"7f63f50e8adbe7f6388b39abb8ab4f5d4d4f0a7c","unresolved":true,"context_lines":[{"line_number":218,"context_line":"            t.join()"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"        for timer in timers_copy:"},{"line_number":221,"context_line":"            timer.join()"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"    def _set_attr(self, obj, attr, value):"},{"line_number":224,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":11,"id":"3f7dc195_e6df7990","line":221,"updated":"2025-04-28 14:38:36.000000000","message":"Traceback (most recent call last):\n  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 98, in run\n    self.service_instance.wait()  # Block until the service stops.\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 209, in wait\n    self.tg.waitall()\n  File \"/opt/stack/oslo.service/oslo_service/backend/threading/threadgroup.py\", line 221, in waitall\n    timer.join()\n    ^^^^^^^^^^\nAttributeError: \u0027FixedIntervalLoopingCall\u0027 object has no attribute \u0027join\u0027","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fbcf7b6ec8a4baf0cce089a8516a5a469368338c","unresolved":false,"context_lines":[{"line_number":218,"context_line":"            t.join()"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"        for timer in timers_copy:"},{"line_number":221,"context_line":"            timer.join()"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"    def _set_attr(self, obj, attr, value):"},{"line_number":224,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":11,"id":"021c78c8_d93767a0","line":221,"in_reply_to":"3f7dc195_e6df7990","updated":"2025-05-02 11:52:10.000000000","message":"Done","commit_id":"2efe5367683039eab2fd58a683524581d820557d"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b478c6faf57ce12eb91d31b69a36e67608ac7be","unresolved":true,"context_lines":[{"line_number":223,"context_line":"            t.join()"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"        for timer in timers_copy:"},{"line_number":226,"context_line":"            timer.stop()"},{"line_number":227,"context_line":"            timer.wait()"},{"line_number":228,"context_line":""},{"line_number":229,"context_line":"    def _set_attr(self, obj, attr, value):"}],"source_content_type":"text/x-python","patch_set":22,"id":"35eb6a53_0097ad88","line":226,"updated":"2025-05-12 12:09:04.000000000","message":"This is called during normal service run:\n```\nMay 12 12:04:25 aio nova-scheduler[130326]: WARNING oslo.service.backend.threading.loopingcall [None req-f8306a95-4b65-48d7-af3b-59c2b50f351e None None]   File \"/usr/lib/python3.12/threading.py\", line 1030, in _bootstrap\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/usr/lib/python3.12/threading.py\", line 1073, in _bootstrap_inner\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/usr/lib/python3.12/threading.py\", line 1010, in run\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/opt/stack/data/venv/lib/python3.12/site-packages/cotyledon/_service.py\", line 140, in _run\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 98, in run\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/opt/stack/oslo.service/oslo_service/backend/threading/service.py\", line 211, in wait\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/opt/stack/oslo.service/oslo_service/backend/threading/threadgroup.py\", line 226, in waitall\nMay 12 12:04:25 aio nova-scheduler[130326]: !!!  File \"/opt/stack/oslo.service/oslo_service/backend/threading/loopingcall.py\", line 117, in stop\n```\n\nCausing that the periodic tasks stopped immediately at the service startup","commit_id":"8872bdab52e8d842795c8834eceb5241a4cb8c7e"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"9277fc531544fd72b5f1bdb12fb13718101438c6","unresolved":true,"context_lines":[{"line_number":223,"context_line":"            t.join()"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"        for timer in timers_copy:"},{"line_number":226,"context_line":"            timer.stop()"},{"line_number":227,"context_line":"            timer.wait()"},{"line_number":228,"context_line":""},{"line_number":229,"context_line":"    def _set_attr(self, obj, attr, value):"}],"source_content_type":"text/x-python","patch_set":22,"id":"43c4f100_2619124b","line":226,"in_reply_to":"35eb6a53_0097ad88","updated":"2025-05-12 12:15:07.000000000","message":"OK. So here we only need to wait but don\u0027t stop the timers. The timers will be stopped via the stop() call when the service needs to stop","commit_id":"8872bdab52e8d842795c8834eceb5241a4cb8c7e"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"1569cfd7f9ce007f3e69f1016f4ea2824a829e87","unresolved":false,"context_lines":[{"line_number":223,"context_line":"            t.join()"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"        for timer in timers_copy:"},{"line_number":226,"context_line":"            timer.stop()"},{"line_number":227,"context_line":"            timer.wait()"},{"line_number":228,"context_line":""},{"line_number":229,"context_line":"    def _set_attr(self, obj, attr, value):"}],"source_content_type":"text/x-python","patch_set":22,"id":"3163ef6a_fbd60d6b","line":226,"in_reply_to":"43c4f100_2619124b","updated":"2025-05-12 14:00:07.000000000","message":"Done","commit_id":"8872bdab52e8d842795c8834eceb5241a4cb8c7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"016610c69f2a710f81560aedf5e72fb8be5b55ff","unresolved":true,"context_lines":[{"line_number":50,"context_line":"        # Python threads cannot be forcefully stopped or cancelled once"},{"line_number":51,"context_line":"        # started. They are kept here to preserve API compatibility with the"},{"line_number":52,"context_line":"        # eventlet backend, where these methods are implemented."},{"line_number":53,"context_line":"        pass"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    def wait(self):"},{"line_number":56,"context_line":"        self.thread.join()"}],"source_content_type":"text/x-python","patch_set":26,"id":"92362333_f4650868","line":53,"updated":"2025-05-13 10:39:42.000000000","message":"Issue a warning maybe? Having stop() as a no-op can cause wait() to never finish","commit_id":"c4afaabc19582e569a04912327ac87b9ca9c10a7"}],"releasenotes/notes/add-threading-backend-9b0e601e5c1282e1.yaml":[{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"ef2a3d473d8f4508d5d0457070760d598a043b7c","unresolved":true,"context_lines":[{"line_number":15,"context_line":"    This backend provides a non-monkey-patched, standard-thread-compatible"},{"line_number":16,"context_line":"    alternative useful for environments where `eventlet` is not suitable."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"    To use this backend, declare the dependency via `[threading_backend]` extra:"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"    ```"},{"line_number":21,"context_line":"    pip install oslo.service[threading_backend]"},{"line_number":22,"context_line":"    ```"}],"source_content_type":"text/x-yaml","patch_set":15,"id":"bd92e388_4d42e713","line":22,"range":{"start_line":18,"start_character":4,"end_line":22,"end_character":7},"updated":"2025-05-05 07:29:40.000000000","message":"I wonder if we want to give usages instructions here. Concerning myself, I\u0027d suggest to not add this section, but this is just a suggestion.","commit_id":"eec7410991acde81c2c136a3c8e6a203193dbd9a"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"45b36954af3f731181320e78af576669d03564aa","unresolved":false,"context_lines":[{"line_number":15,"context_line":"    This backend provides a non-monkey-patched, standard-thread-compatible"},{"line_number":16,"context_line":"    alternative useful for environments where `eventlet` is not suitable."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"    To use this backend, declare the dependency via `[threading_backend]` extra:"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"    ```"},{"line_number":21,"context_line":"    pip install oslo.service[threading_backend]"},{"line_number":22,"context_line":"    ```"}],"source_content_type":"text/x-yaml","patch_set":15,"id":"f032e982_aa932435","line":22,"range":{"start_line":18,"start_character":4,"end_line":22,"end_character":7},"in_reply_to":"a603cebc_008561d0","updated":"2025-05-05 10:06:44.000000000","message":"Done","commit_id":"eec7410991acde81c2c136a3c8e6a203193dbd9a"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"d90363ffd2831edea978e95121bdbbfa7ba81e60","unresolved":true,"context_lines":[{"line_number":15,"context_line":"    This backend provides a non-monkey-patched, standard-thread-compatible"},{"line_number":16,"context_line":"    alternative useful for environments where `eventlet` is not suitable."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"    To use this backend, declare the dependency via `[threading_backend]` extra:"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"    ```"},{"line_number":21,"context_line":"    pip install oslo.service[threading_backend]"},{"line_number":22,"context_line":"    ```"}],"source_content_type":"text/x-yaml","patch_set":15,"id":"a603cebc_008561d0","line":22,"range":{"start_line":18,"start_character":4,"end_line":22,"end_character":7},"in_reply_to":"bd92e388_4d42e713","updated":"2025-05-05 10:04:14.000000000","message":"Ok I will remove it. You probably right.","commit_id":"eec7410991acde81c2c136a3c8e6a203193dbd9a"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"fc411fe0e220bb8f9d5c497e0a5da1327c3e8e45","unresolved":true,"context_lines":[{"line_number":19,"context_line":"    - `ProcessLauncher` now supports a `no_fork\u003dTrue` mode, allowing services"},{"line_number":20,"context_line":"      to run in the main process without forking. This is useful when `fork()`"},{"line_number":21,"context_line":"      is unsafe, such as in threaded environments or with Python 3.12+ where"},{"line_number":22,"context_line":"      the default multiprocessing start method is `spawn`."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    - A new `register_backend_default_hook()` API has been added, allowing users"},{"line_number":25,"context_line":"      to specify a fallback backend type in case `init_backend()` has not been"}],"source_content_type":"text/x-yaml","patch_set":20,"id":"f2d9f305_e16080fe","line":22,"updated":"2025-05-12 07:43:47.000000000","message":"I would add an `issues:` section to the release notes to warn the users that if they start threads before the oslo.service backend is asked to fork the worker processes then that will lead to corrupted state. (The long version of a possible bug with this is documented in https://gibizer.github.io/posts/Eventlet-Removal-The-First-Threading-Bug/#threads--osfork--confused-threadpools) In the `issue` I would suggest to either:\n* do not start threads before the fork or\n* use the no_fork mode or\n* implement a specific solution to avoid the problem, like stopping threads before the fork. (nova\u0027s current solution)","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"3d582e7df2475092f81b5063fc18620d666276ad","unresolved":false,"context_lines":[{"line_number":19,"context_line":"    - `ProcessLauncher` now supports a `no_fork\u003dTrue` mode, allowing services"},{"line_number":20,"context_line":"      to run in the main process without forking. This is useful when `fork()`"},{"line_number":21,"context_line":"      is unsafe, such as in threaded environments or with Python 3.12+ where"},{"line_number":22,"context_line":"      the default multiprocessing start method is `spawn`."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    - A new `register_backend_default_hook()` API has been added, allowing users"},{"line_number":25,"context_line":"      to specify a fallback backend type in case `init_backend()` has not been"}],"source_content_type":"text/x-yaml","patch_set":20,"id":"11b60780_6d397549","line":22,"in_reply_to":"baa7348b_6872a7bb","updated":"2025-05-12 10:26:33.000000000","message":"Done","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"249c9ba5ce6029d2064ce29aee42e2706d66ab19","unresolved":true,"context_lines":[{"line_number":19,"context_line":"    - `ProcessLauncher` now supports a `no_fork\u003dTrue` mode, allowing services"},{"line_number":20,"context_line":"      to run in the main process without forking. This is useful when `fork()`"},{"line_number":21,"context_line":"      is unsafe, such as in threaded environments or with Python 3.12+ where"},{"line_number":22,"context_line":"      the default multiprocessing start method is `spawn`."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    - A new `register_backend_default_hook()` API has been added, allowing users"},{"line_number":25,"context_line":"      to specify a fallback backend type in case `init_backend()` has not been"}],"source_content_type":"text/x-yaml","patch_set":20,"id":"baa7348b_6872a7bb","line":22,"in_reply_to":"f2d9f305_e16080fe","updated":"2025-05-12 10:24:19.000000000","message":"Thanks a lot again. I will do that!","commit_id":"3f1cede533482d7b0260f24caa2ce819fb7a2d56"}],"setup.cfg":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":22,"context_line":"    Programming Language :: Python :: 3 :: Only"},{"line_number":23,"context_line":"    Programming Language :: Python :: Implementation :: CPython"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"[options.extras_require]"},{"line_number":26,"context_line":"threading_backend \u003d"},{"line_number":27,"context_line":"    cotyledon\u003e\u003d2.0.0"},{"line_number":28,"context_line":"    futurist\u003e\u003d3.1.1"}],"source_content_type":"text/x-ttcn-cfg","patch_set":19,"id":"e3d050ba_fc43d80d","line":25,"range":{"start_line":25,"start_character":1,"end_line":25,"end_character":23},"updated":"2025-05-07 13:01:50.000000000","message":"The extras section, which is translated by pbr, is more commonly used","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"cfa8be8f4e0f89fb6fd6447565eab043420c9823","unresolved":true,"context_lines":[{"line_number":22,"context_line":"    Programming Language :: Python :: 3 :: Only"},{"line_number":23,"context_line":"    Programming Language :: Python :: Implementation :: CPython"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"[options.extras_require]"},{"line_number":26,"context_line":"threading_backend \u003d"},{"line_number":27,"context_line":"    cotyledon\u003e\u003d2.0.0"},{"line_number":28,"context_line":"    futurist\u003e\u003d3.1.1"}],"source_content_type":"text/x-ttcn-cfg","patch_set":19,"id":"e69b8ebc_6692425d","line":25,"range":{"start_line":25,"start_character":1,"end_line":25,"end_character":23},"in_reply_to":"e3d050ba_fc43d80d","updated":"2025-05-12 10:45:53.000000000","message":"Thanks a lot! As far as I know, the [options.extras_require] section is already handled properly by pbr, so this should behave like any standard extras definition. But let me know if you meant something else or saw a specific issue with this format.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"554413dac1e030ffed8329f002a0448a19ac04dc","unresolved":false,"context_lines":[{"line_number":22,"context_line":"    Programming Language :: Python :: 3 :: Only"},{"line_number":23,"context_line":"    Programming Language :: Python :: Implementation :: CPython"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"[options.extras_require]"},{"line_number":26,"context_line":"threading_backend \u003d"},{"line_number":27,"context_line":"    cotyledon\u003e\u003d2.0.0"},{"line_number":28,"context_line":"    futurist\u003e\u003d3.1.1"}],"source_content_type":"text/x-ttcn-cfg","patch_set":19,"id":"823efa4a_8879559e","line":25,"range":{"start_line":25,"start_character":1,"end_line":25,"end_character":23},"in_reply_to":"e69b8ebc_6692425d","updated":"2025-05-12 11:59:14.000000000","message":"I\u0027m ok with keeping this now, seeing some activity to deprecate pbr specific options.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":23,"context_line":"    Programming Language :: Python :: Implementation :: CPython"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"[options.extras_require]"},{"line_number":26,"context_line":"threading_backend \u003d"},{"line_number":27,"context_line":"    cotyledon\u003e\u003d2.0.0"},{"line_number":28,"context_line":"    futurist\u003e\u003d3.1.1"},{"line_number":29,"context_line":""}],"source_content_type":"text/x-ttcn-cfg","patch_set":19,"id":"e74c76c5_7872c623","line":26,"range":{"start_line":26,"start_character":0,"end_line":26,"end_character":17},"updated":"2025-05-07 13:01:50.000000000","message":"Can we just name this threading or even native ? backend sounds a bit redundant to me.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"dcce3ba052e74619da4f86bcbf06063e37425164","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    Programming Language :: Python :: Implementation :: CPython"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"[options.extras_require]"},{"line_number":26,"context_line":"threading_backend \u003d"},{"line_number":27,"context_line":"    cotyledon\u003e\u003d2.0.0"},{"line_number":28,"context_line":"    futurist\u003e\u003d3.1.1"},{"line_number":29,"context_line":""}],"source_content_type":"text/x-ttcn-cfg","patch_set":19,"id":"c3e137ce_cfc18e7e","line":26,"range":{"start_line":26,"start_character":0,"end_line":26,"end_character":17},"in_reply_to":"e74c76c5_7872c623","updated":"2025-05-12 10:51:05.000000000","message":"Done","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"}],"setup.py":[{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"d708da807dad24917c34f03e87c48448ff5ff96f","unresolved":true,"context_lines":[{"line_number":17,"context_line":""},{"line_number":18,"context_line":"setuptools.setup("},{"line_number":19,"context_line":"    setup_requires\u003d[\u0027pbr\u003e\u003d2.0.0\u0027],"},{"line_number":20,"context_line":"    extras_require\u003d{"},{"line_number":21,"context_line":"        \"threading_backend\": [\"futurist\", \"cotyledon\"],"},{"line_number":22,"context_line":"    },"},{"line_number":23,"context_line":"    pbr\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":12,"id":"79a367b3_b62cb83c","line":22,"range":{"start_line":20,"start_character":0,"end_line":22,"end_character":6},"updated":"2025-04-30 11:58:47.000000000","message":"I\u0027d suggest to move that to the `setup.cfg` file into the `extra` section, like in other oslo deliverables (e.g https://opendev.org/openstack/oslo.messaging/src/branch/master/setup.cfg#L25-L30)\n\nI think it will fix the problem identified by gibi (see his comments above)","commit_id":"712a7f47830a291f32f74129816d4ea6b3baaeb2"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fbcf7b6ec8a4baf0cce089a8516a5a469368338c","unresolved":false,"context_lines":[{"line_number":17,"context_line":""},{"line_number":18,"context_line":"setuptools.setup("},{"line_number":19,"context_line":"    setup_requires\u003d[\u0027pbr\u003e\u003d2.0.0\u0027],"},{"line_number":20,"context_line":"    extras_require\u003d{"},{"line_number":21,"context_line":"        \"threading_backend\": [\"futurist\", \"cotyledon\"],"},{"line_number":22,"context_line":"    },"},{"line_number":23,"context_line":"    pbr\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":12,"id":"902749b5_ec5f4bcd","line":22,"range":{"start_line":20,"start_character":0,"end_line":22,"end_character":6},"in_reply_to":"79a367b3_b62cb83c","updated":"2025-05-02 11:52:10.000000000","message":"Done","commit_id":"712a7f47830a291f32f74129816d4ea6b3baaeb2"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"f33bd40408b7b26e7ae32d2e91625f4335f35e68","unresolved":true,"context_lines":[{"line_number":15,"context_line":""},{"line_number":16,"context_line":"import setuptools"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"setuptools.setup(setup_requires\u003d[\u0027pbr\u003e\u003d2.0.0\u0027], pbr\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":19,"id":"bd128098_80a64515","line":18,"range":{"start_line":18,"start_character":17,"end_line":18,"end_character":57},"updated":"2025-05-07 13:01:50.000000000","message":"Any reason for this change ?","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"15d92435ca207c22611c0a4bbe24a3f755037082","unresolved":true,"context_lines":[{"line_number":15,"context_line":""},{"line_number":16,"context_line":"import setuptools"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"setuptools.setup(setup_requires\u003d[\u0027pbr\u003e\u003d2.0.0\u0027], pbr\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":19,"id":"cb65d0a0_fb1a52b2","line":18,"range":{"start_line":18,"start_character":17,"end_line":18,"end_character":57},"in_reply_to":"bd128098_80a64515","updated":"2025-05-07 13:15:22.000000000","message":"That\u0027s a side effect of a previous patch set, indeed, it can be reverted at the initial status before this whole patch.","commit_id":"9f18f7aa9bf329025638dd0eca1249502b9ab464"}]}
