)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"e6555345987fe3680af71d0a4fe35faff8587979","unresolved":true,"context_lines":[{"line_number":4,"context_line":"Commit:     Daniel Bengtsson \u003cdbengt@redhat.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-02-06 16:41:38 +0100"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add run_periodic_tasks_in_parallel() using spawn-based process pool"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Add a new method to run due periodic tasks in parallel via a"},{"line_number":10,"context_line":"spawn-based process pool, so callers (e.g. services that schedule"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"fd809192_e6e221cd","line":7,"range":{"start_line":7,"start_character":0,"end_line":7,"end_character":67},"updated":"2026-02-06 15:58:21.000000000","message":"```suggestion\nSupport running periodic tasks in parallel\n```","commit_id":"3ae6bb18c956a531a1d0fba27263f1528e025aa6"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"0178f6f83cbd6e8deb2c6f24705c91094e46669c","unresolved":false,"context_lines":[{"line_number":4,"context_line":"Commit:     Daniel Bengtsson \u003cdbengt@redhat.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-02-06 16:41:38 +0100"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add run_periodic_tasks_in_parallel() using spawn-based process pool"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Add a new method to run due periodic tasks in parallel via a"},{"line_number":10,"context_line":"spawn-based process pool, so callers (e.g. services that schedule"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"2d0cf7e1_98d61a43","line":7,"range":{"start_line":7,"start_character":0,"end_line":7,"end_character":67},"in_reply_to":"fd809192_e6e221cd","updated":"2026-02-06 16:15:31.000000000","message":"Done","commit_id":"3ae6bb18c956a531a1d0fba27263f1528e025aa6"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"8305b70a08c198c001f2773b8b80671270fdc15f","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"e4ce5984_6cb4169f","updated":"2026-02-05 14:13:57.000000000","message":"A few questions\n\n- Does this work in eventlet environment ? I guess no, then we should not allow it used in eventlet\n\n- Also I\u0027m unsure if this the expected behavior really, given the fact that the behavior has been identical in both eventlet and threading. For example I see nova uses tg.add_dynamic_timer to run this method. Should we rather fix oslo_service.backend._threading.threadgroup.ThreadGroup instead ?","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"02fb475b0c1ca2bd6e81b5a3ea1f6e34f817bd08","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"cae50ebc_fc963342","in_reply_to":"2a58ec8d_8dd05536","updated":"2026-05-06 13:36:12.000000000","message":"Done","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"c173e0dd16eeb9af1b2b4e9a6341d9617525ffc5","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"2a58ec8d_8dd05536","in_reply_to":"436264ef_3466937f","updated":"2026-02-06 15:31:36.000000000","message":"Could you then refine your commit message accordingly, then?\n\nThe title indicates that you are fixing an existing deadlock or any other problem in current PeriodicTask.run_periodic_tasks, but in fact you are just adding the new functionality to run periodic tasks in paralellel. This is quite confusing IMHO.\n\nAlso please consider removing any mention to potential deadlock from release note because you are adding this feature implemented in a way which does not bring such concern.","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"c6b8b81de398ce151839db5f29e6d6796f25de8e","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"436264ef_3466937f","in_reply_to":"b396d7ad_92c9539b","updated":"2026-02-06 15:24:11.000000000","message":"The multiprocessing pool is created in the new run_periodic_tasks_in_parallel() method added by this change (see line 291 in oslo_service/periodic_task.py):\n\npool \u003d _multiprocessing.get_spawn_pool(processes\u003dprocesses)\n\n\nThis is the only place where concurrency is introduced.\nThe existing run_periodic_tasks() method is unchanged and still executes due tasks sequentially, without any process pool.\n\nThe phrase “services that run periodic tasks in parallel” in the commit message refers to services explicitly calling run_periodic_tasks_in_parallel() (for example via tg.add_dynamic_timer in Nova), not to run_periodic_tasks(), which remains strictly sequential.","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"ead98c4c2c41fdd3023f8366e07c1f21e8f49549","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"ea439d12_ca54aa91","in_reply_to":"d5bc8a8b_059ae94d","updated":"2026-02-05 22:52:33.000000000","message":"Done","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"037f1b4d62cd2a7a79b34db36726b0437e87f35d","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"d5bc8a8b_059ae94d","in_reply_to":"e4ce5984_6cb4169f","updated":"2026-02-05 22:52:23.000000000","message":"The deadlock/hang is caused by the multiprocessing pool created by the callback (this method) when it is invoked from a threaded context (e.g. via tg.add_dynamic_timer). ThreadGroup only schedules and executes the callback in a thread; it does not manage process pools. Therefore, the correct place to address this is where the pool is created, i.e. run_periodic_tasks_in_parallel() (using a spawn-based pool). Nova calling this via add_dynamic_timer is exactly the scenario this change targets.","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"07d55478f19b689fea47115c50d67c5bf03144ef","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"b396d7ad_92c9539b","in_reply_to":"ea439d12_ca54aa91","updated":"2026-02-06 15:08:55.000000000","message":"Could you please point where that multiprocessing pool is created by PeriodicTasks ? I don\u0027t see any concurrency mechanism implemented withint PeriodicTasks itself.\n\nSo what confuses me at this point is \"Services that run periodic tasks in parallel\" you mentioned in the commit message. PeriodicTask.run_periodic_tasks executes the registered tasks one by one and has no parallel mechanism. We don\u0027t expect it to be executed in parallel, either.","commit_id":"580479284c7e33efc0fdc26fc419429d6f475808"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"6c0e614ad67193c12939274e96577376e525285f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"08c81aff_4851a73f","updated":"2026-02-06 16:20:37.000000000","message":"LGTM, comments seems addressed","commit_id":"7a8b57828c4a918b334de2a9b9362cf02d73f7fe"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"de05a5676cb60693ad869848a8131b443e6e9b85","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"33fee276_671e89ee","updated":"2026-02-06 18:50:29.000000000","message":"lgtm, one comment for better error message but not blocker.\n\npep8 failure is valid and needs to be fixed to pass gate.","commit_id":"7a8b57828c4a918b334de2a9b9362cf02d73f7fe"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"93ed5dab6f91af895ac143f87cc5dafe42b08086","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"d0a37f83_895161ba","updated":"2026-02-23 10:01:24.000000000","message":"LGTM, I agree with gmaan\u0027s comment, but as said it could be done into a follow up.","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"e9a4ddf6e25b2396f3343a686114e63b71354495","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"38aa60a6_4db74322","updated":"2026-02-09 10:34:03.000000000","message":"recheck","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"5f530c36d5b9931edfd8b761198c63d2f53a931e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"42ec41cd_9a9a09a1","updated":"2026-02-09 08:16:16.000000000","message":"recheck","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"e598e21ab29f77282b50c28d7e2ebaa59fed9c07","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"5b473002_0b2dd03f","updated":"2026-02-08 16:09:39.000000000","message":"recheck","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"ea30584c0751146b8c77f9e56e652a95694c3232","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"5c74a292_29ce673a","updated":"2026-02-09 09:03:32.000000000","message":"recheck","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"89dea864c5af8a1f1fb42e71f014b6a46ad644d2","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"b61ecd42_d626afe2","updated":"2026-02-12 18:16:11.000000000","message":"recheck gate is green now. lgtm,","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"48fd81820609cb145d67913c94021cdb975d0c83","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"db247bbc_eadcc766","updated":"2026-02-11 20:43:42.000000000","message":"tempest-full job is broken, we need to wait until https://review.opendev.org/c/openstack/tempest/+/976501 is merged","commit_id":"209aac2c4960273c8a890a0ea5fdda38c20067c3"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"e5cfa6c196720c1a1edb6fb4ef4a6f5a0659c838","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"356367e9_1c9e85a9","updated":"2026-03-02 18:33:28.000000000","message":"thanks for update, lgtm","commit_id":"2276652f8cdcba669fa2d92fac427dbeb32523ef"},{"author":{"_account_id":38752,"name":"Pavlo Kostianov","email":"pkostian@redhat.com","username":"pkostian"},"change_message_id":"96ef47232fe2f967ef152aa1fce75480a43bba28","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"ef28cfcf_c6a2aebf","updated":"2026-03-10 18:16:56.000000000","message":"I\u0027ve suggested a minor improvement, LGTM to everything else","commit_id":"9ab14460206913c1e61478384bbb76072041fe96"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"283587b2ad89a284e9635886ba2bbaacd24a5cf8","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":11,"id":"59f96e03_7ce1a339","updated":"2026-03-23 15:14:28.000000000","message":"The change looks good to me at this moment. Leave a minor documentation problem.\n\nAlso, do you have any specific PoC code which uses this feature in actual services ?","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"02fb475b0c1ca2bd6e81b5a3ea1f6e34f817bd08","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"f963cb53_50f2b2d4","in_reply_to":"59f96e03_7ce1a339","updated":"2026-05-06 13:36:12.000000000","message":"Done","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":38752,"name":"Pavlo Kostianov","email":"pkostian@redhat.com","username":"pkostian"},"change_message_id":"9c5ff8001fd47c8b68d18966d59a29774dd83e77","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":13,"id":"22a3deed_f8cb2ff3","updated":"2026-04-16 13:37:38.000000000","message":"LGTM. For an initial implementation this patch is a reasonable starting point","commit_id":"556682d955cc2bc8f8f75c2f1ab72e1a5609dbf7"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"a67e35589db4eff87e20c3ebfd0beba295eb4b34","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"4927a24c_d03931a4","updated":"2026-05-07 10:22:35.000000000","message":"I still believe this is not optimal because the whole periodic execution can be blocked by a single task taking long time, but I unlikely have time to provide alternative solution I\u0027m ok to merge this.\n\nNote that honestly I\u0027m very concerned about the fact that the features we recently introduced (threading backend, threading context, etc) were too often found broken later when we actually attempt to use these in real service. I\u0027m hoping that we get actual progress in real services to use this feature to find out any problems during this cycle.","commit_id":"6c1b7f810b61963b85e6f6bd1d3450317596eb85"},{"author":{"_account_id":28522,"name":"Hervé Beraud","email":"herveberaud.pro@gmail.com","username":"hberaud"},"change_message_id":"7472c8d4ff32fbdd9dc4a27f60894756ea3e56e1","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"4df28a84_5d255b13","updated":"2026-05-07 08:44:31.000000000","message":"LGTM, Takashi\u0027s comments seems addressed","commit_id":"6c1b7f810b61963b85e6f6bd1d3450317596eb85"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"ba50df1f92b97ac27e43941bb3b183c1c010e4ee","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"41ae54ff_1dd3db92","in_reply_to":"4927a24c_d03931a4","updated":"2026-05-07 12:11:04.000000000","message":"Thanks a lot Takashi, that makes sense.\n\nI agree this is not yet the final optimal model, especially regarding long-running tasks.\n\nI already opened a follow-up patch for that specific concern:\n\nhttps://review.opendev.org/c/openstack/oslo.service/+/982418\n\nThat follow-up changes the result collection logic to poll AsyncResult.ready() and drain completed tasks as workers finish, instead of collecting strictly in submission order.\n\nMy intention here was to keep this patch focused on introducing the spawn-based parallel execution path first, then improve the scheduling/result collection behavior incrementally in follow-ups.\n\nI also agree that exercising this in real services during this cycle will be important to uncover remaining threading/spawn issues outside unit tests.","commit_id":"6c1b7f810b61963b85e6f6bd1d3450317596eb85"}],"oslo_service/periodic_task.py":[{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"de05a5676cb60693ad869848a8131b443e6e9b85","unresolved":true,"context_lines":[{"line_number":246,"context_line":"        logging). Fork would inherit those locks in child processes; spawn"},{"line_number":247,"context_line":"        starts fresh processes."},{"line_number":248,"context_line":""},{"line_number":249,"context_line":"        The service instance (self) and context must be picklable when using"},{"line_number":250,"context_line":"        this method."},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"        :param context: Passed to each periodic task."},{"line_number":253,"context_line":"        :param raise_on_error: If True, re-raise the first task exception."}],"source_content_type":"text/x-python","patch_set":7,"id":"5192a282_20353079","line":250,"range":{"start_line":249,"start_character":0,"end_line":250,"end_character":20},"updated":"2026-02-06 18:50:29.000000000","message":"can we check this using ForkingPickler.dumps(service_instance) and return with better error message like we do in Launcher?\n\nIt can be done in followup though","commit_id":"7a8b57828c4a918b334de2a9b9362cf02d73f7fe"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"624f65c0064e3237b11d38d0f01ec3347433f676","unresolved":false,"context_lines":[{"line_number":246,"context_line":"        logging). Fork would inherit those locks in child processes; spawn"},{"line_number":247,"context_line":"        starts fresh processes."},{"line_number":248,"context_line":""},{"line_number":249,"context_line":"        The service instance (self) and context must be picklable when using"},{"line_number":250,"context_line":"        this method."},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"        :param context: Passed to each periodic task."},{"line_number":253,"context_line":"        :param raise_on_error: If True, re-raise the first task exception."}],"source_content_type":"text/x-python","patch_set":7,"id":"d1937231_530aac27","line":250,"range":{"start_line":249,"start_character":0,"end_line":250,"end_character":20},"in_reply_to":"5192a282_20353079","updated":"2026-03-02 14:41:21.000000000","message":"Done","commit_id":"7a8b57828c4a918b334de2a9b9362cf02d73f7fe"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"de05a5676cb60693ad869848a8131b443e6e9b85","unresolved":false,"context_lines":[{"line_number":306,"context_line":"                    LOG.exception(\"Error during %(full_task_name)s\","},{"line_number":307,"context_line":"                                  {\"full_task_name\": full_task_name})"},{"line_number":308,"context_line":"        finally:"},{"line_number":309,"context_line":"            pool.close()"},{"line_number":310,"context_line":"            pool.join()"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        return idle_for"}],"source_content_type":"text/x-python","patch_set":7,"id":"65bbbaf8_ef8f114a","line":309,"range":{"start_line":309,"start_character":0,"end_line":309,"end_character":24},"updated":"2026-02-06 18:50:29.000000000","message":"++","commit_id":"7a8b57828c4a918b334de2a9b9362cf02d73f7fe"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"e5cfa6c196720c1a1edb6fb4ef4a6f5a0659c838","unresolved":false,"context_lines":[{"line_number":291,"context_line":""},{"line_number":292,"context_line":"        try:"},{"line_number":293,"context_line":"            ForkingPickler.dumps(self)"},{"line_number":294,"context_line":"            ForkingPickler.dumps(context)"},{"line_number":295,"context_line":"        except Exception:"},{"line_number":296,"context_line":"            LOG.error("},{"line_number":297,"context_line":"                \"Service %s or context is not picklable with spawn. \""}],"source_content_type":"text/x-python","patch_set":9,"id":"1cb510af_6cf070f1","line":294,"range":{"start_line":294,"start_character":11,"end_line":294,"end_character":41},"updated":"2026-03-02 18:33:28.000000000","message":"++","commit_id":"2276652f8cdcba669fa2d92fac427dbeb32523ef"},{"author":{"_account_id":38752,"name":"Pavlo Kostianov","email":"pkostian@redhat.com","username":"pkostian"},"change_message_id":"96ef47232fe2f967ef152aa1fce75480a43bba28","unresolved":false,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":10,"id":"17fc555b_67fa0e04","line":315,"range":{"start_line":315,"start_character":0,"end_line":315,"end_character":2},"updated":"2026-03-10 18:16:56.000000000","message":"Consider adding timeout to result.get() to prevent eternal blocking if a task hangs:\n\n      result.get(timeout\u003dself.conf.periodic_task_timeout)\n\nWithout this, a single hung task can block all future periodic task execution and prevent graceful shutdown.","commit_id":"9ab14460206913c1e61478384bbb76072041fe96"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"4efbdfbb7a40236aca66064a725cfa4b21e09356","unresolved":false,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":10,"id":"7ccfb471_8d56e021","line":315,"range":{"start_line":315,"start_character":0,"end_line":315,"end_character":2},"in_reply_to":"17fc555b_67fa0e04","updated":"2026-03-11 15:41:24.000000000","message":"Good point. A timeout would avoid indefinite blocking if a task hangs.\n\nI\u0027d prefer to handle this in a follow-up change, since we would need to\nintroduce a periodic_task_timeout config option and define the behavior on\ntimeout (e.g. log and continue vs. pool shutdown).\n\nI will consider proposing a follow-up patch for this improvement.","commit_id":"9ab14460206913c1e61478384bbb76072041fe96"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"283587b2ad89a284e9635886ba2bbaacd24a5cf8","unresolved":true,"context_lines":[{"line_number":247,"context_line":"        logging). Fork would inherit those locks in child processes; spawn"},{"line_number":248,"context_line":"        starts fresh processes."},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"        The service instance (self) and context must be picklable when using"},{"line_number":251,"context_line":"        this method."},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"        :param context: Passed to each periodic task."}],"source_content_type":"text/x-python","patch_set":11,"id":"78077e7a_1ccf7401","line":250,"range":{"start_line":250,"start_character":12,"end_line":250,"end_character":19},"updated":"2026-03-23 15:14:28.000000000","message":"PeriodicTasks ?","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"90cd89a181ca2395e780d82c5f49e53f3e601838","unresolved":false,"context_lines":[{"line_number":247,"context_line":"        logging). Fork would inherit those locks in child processes; spawn"},{"line_number":248,"context_line":"        starts fresh processes."},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"        The service instance (self) and context must be picklable when using"},{"line_number":251,"context_line":"        this method."},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"        :param context: Passed to each periodic task."}],"source_content_type":"text/x-python","patch_set":11,"id":"9184a5f9_8f027b00","line":250,"range":{"start_line":250,"start_character":12,"end_line":250,"end_character":19},"in_reply_to":"78077e7a_1ccf7401","updated":"2026-03-27 13:22:37.000000000","message":"Done","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"283587b2ad89a284e9635886ba2bbaacd24a5cf8","unresolved":true,"context_lines":[{"line_number":294,"context_line":"            ForkingPickler.dumps(context)"},{"line_number":295,"context_line":"        except Exception:"},{"line_number":296,"context_line":"            LOG.error("},{"line_number":297,"context_line":"                \"Service %s or context is not picklable with spawn. \""},{"line_number":298,"context_line":"                \"Make the service instance and context spawn-safe for \""},{"line_number":299,"context_line":"                \"parallel periodic tasks.\","},{"line_number":300,"context_line":"                type(self).__name__,"}],"source_content_type":"text/x-python","patch_set":11,"id":"1df3e9f8_84bc8b0d","line":297,"range":{"start_line":297,"start_character":17,"end_line":297,"end_character":24},"updated":"2026-03-23 15:14:28.000000000","message":"PeriodicTasks ?","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"90cd89a181ca2395e780d82c5f49e53f3e601838","unresolved":false,"context_lines":[{"line_number":294,"context_line":"            ForkingPickler.dumps(context)"},{"line_number":295,"context_line":"        except Exception:"},{"line_number":296,"context_line":"            LOG.error("},{"line_number":297,"context_line":"                \"Service %s or context is not picklable with spawn. \""},{"line_number":298,"context_line":"                \"Make the service instance and context spawn-safe for \""},{"line_number":299,"context_line":"                \"parallel periodic tasks.\","},{"line_number":300,"context_line":"                type(self).__name__,"}],"source_content_type":"text/x-python","patch_set":11,"id":"abe20389_824dcf62","line":297,"range":{"start_line":297,"start_character":17,"end_line":297,"end_character":24},"in_reply_to":"1df3e9f8_84bc8b0d","updated":"2026-03-27 13:22:37.000000000","message":"Done","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"18ce24d7b4f1ad288f917ecb41bc81e1e0851626","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"0f7771d3_837f3b3f","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"updated":"2026-03-25 17:03:30.000000000","message":"I wonder if you considered using result.ready() to check whether the task is actually completed ? It may probably allow you to check completed tasks more timely even when a few of these take long time. (though it requires that we retry result check for several time with interval like 1 second)","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"e42fc32f50b1b129fde785b2de6282c5f983bb4f","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"7fb8f2cc_0bfd25c4","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"0f7771d3_837f3b3f","updated":"2026-03-27 13:20:59.000000000","message":"Good point. I chose the simpler sequential result.get() approach first \nto keep the initial implementation straightforward and predictable.\n\nUsing result.ready() with polling could help detect completed tasks \nearlier when some take much longer than others, but it would also add \nextra scheduling logic here.\n\nI\u0027d prefer to keep this version simple for now and consider that as a \nfollow-up improvement if we find it necessary in practice.","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"b83e921369ef8f46806c059689df81152d680720","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"3168ad84_1ba83bad","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"1290afbf_9c57169d","updated":"2026-03-27 16:52:08.000000000","message":"So do you intend to mere that follow-up or not ? I\u0027m afraid your two comments are conflicting.\n\nAlso please check my comment in https://review.opendev.org/c/openstack/oslo.service/+/981302 .","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"370757a0a40223680db55f5ff8223b1ee68a5a5e","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"d9b2acfb_bc970e5b","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"16236a74_ae4d3ead","updated":"2026-04-16 14:56:42.000000000","message":"As I mentioned in https://review.opendev.org/c/openstack/oslo.service/+/975785/comments/59f96e03_7ce1a339 earlier, Do you have real PoC code which attempts to use this new implementations in any of the existing OpenStack services ? I really want to see how efficient it would be in existing usage before we merge this, and it\u0027s quite difficult to predict that without any actual experiments.","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"bbb7dd81525a07ced553106b6f38b3d602d0c3e9","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"fdbc1f0c_086dc847","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"3168ad84_1ba83bad","updated":"2026-03-30 10:28:32.000000000","message":"Yes, the ready()-based polling is intended as a follow-up\nimprovement, but my plan is to merge this patch first\nas the base implementation.\n\nThe follow-up change will be proposed separately once\nthis one is merged.","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"fed2303faa7845c4ae612fe2e7ea592972aa5f5c","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"1290afbf_9c57169d","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"7fb8f2cc_0bfd25c4","updated":"2026-03-27 13:58:10.000000000","message":"Good point. I have implemented a follow-up change to use result.ready()\nfor polling completed tasks.\n\nThe proposal is available here:\nhttps://review.opendev.org/c/openstack/oslo.service/+/982418","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"04f6690ac5bfed49161c7228f019986d7046afdb","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"16236a74_ae4d3ead","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"a41d91a3_01164a3d","updated":"2026-04-15 10:11:21.000000000","message":"The goal of this series is to first introduce parallel periodic task execution using a spawn-based pool in a simple and predictable way, and then incrementally improve robustness.\n\nThe base patch adds the parallel execution capability with the simplest result collection model (`result.get()`).\n\nThe timeout change (981302) is meant as a robustness improvement to avoid blocking indefinitely when a task or pool shutdown hangs. It does not change the execution model itself.\n\nThe ready()-based polling change was proposed as an optional follow-up to improve responsiveness when tasks have very different execution times, but it is not required for the initial implementation.\n\nRegarding your concern about inefficient concurrency within a single run, that is a valid point. My intention here is to keep the initial implementation simple, but I\u0027m open to adjusting the approach if we confirm that the current result collection significantly limits concurrency in real scenarios.","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"8db2691529dd6b7f992cf50cbc46e9ec54b0e4ac","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"e7fd5a6e_85d40dce","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"d9b2acfb_bc970e5b","updated":"2026-05-06 13:35:39.000000000","message":"Thanks a lot for the feedback. I have added a small PoC under tools/\n(poc_run_periodic_tasks_in_parallel.py) to demonstrate the intended usage.\n\nIt runs multiple due periodic tasks using run_periodic_tasks_in_parallel()\nwith the threading backend and a spawn-based process pool, showing:\n\n- overlapping task execution,\n- multiple worker PIDs,\n- reduced wall time compared to sequential execution.\n\nThis is meant to make the behavior more concrete. I agree that evaluating\nefficiency in real services is important, and this PoC is a first step in\nthat direction.","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"02fb475b0c1ca2bd6e81b5a3ea1f6e34f817bd08","unresolved":false,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"60be0eae_25d88f47","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"e7fd5a6e_85d40dce","updated":"2026-05-06 13:36:12.000000000","message":"Done","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"cddb824e8ce137c43efdf600d3dac996b1a89448","unresolved":true,"context_lines":[{"line_number":312,"context_line":""},{"line_number":313,"context_line":"            for full_task_name, result in async_results:"},{"line_number":314,"context_line":"                try:"},{"line_number":315,"context_line":"                    result.get()"},{"line_number":316,"context_line":"                except BaseException:"},{"line_number":317,"context_line":"                    if raise_on_error:"},{"line_number":318,"context_line":"                        raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"a41d91a3_01164a3d","line":315,"range":{"start_line":315,"start_character":27,"end_line":315,"end_character":30},"in_reply_to":"fdbc1f0c_086dc847","updated":"2026-04-07 16:09:43.000000000","message":"Could you please explain a bit about the ideal goal of this series ? That ready change is actually conflicting with your subsequent change https://review.opendev.org/c/openstack/oslo.service/+/981302 .\n\nAlso I\u0027m mainly concerned about the comment I left in https://review.opendev.org/c/openstack/oslo.service/+/981302 , regarding the inefficient concurrency caused by threadpool usage within single run, as I explained multiple times in IRC. If that concern is valid then the current approach needs adjustment.","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":38752,"name":"Pavlo Kostianov","email":"pkostian@redhat.com","username":"pkostian"},"change_message_id":"32034973fc2358e2c4be5782762ea6b4e841c1a3","unresolved":true,"context_lines":[{"line_number":282,"context_line":""},{"line_number":283,"context_line":"            LOG.debug(\"Running periodic task %(full_task_name)s (parallel)\","},{"line_number":284,"context_line":"                      {\"full_task_name\": full_task_name})"},{"line_number":285,"context_line":"            self._periodic_last_run[task_name] \u003d _nearest_boundary("},{"line_number":286,"context_line":"                last_run, spacing)"},{"line_number":287,"context_line":"            due_tasks.append((full_task_name, task_name, task))"},{"line_number":288,"context_line":""},{"line_number":289,"context_line":"        if not due_tasks:"},{"line_number":290,"context_line":"            return idle_for"}],"source_content_type":"text/x-python","patch_set":12,"id":"b59191fe_6ae25c49","line":287,"range":{"start_line":285,"start_character":0,"end_line":287,"end_character":63},"updated":"2026-04-13 12:39:41.000000000","message":"_periodic_last_run is updated here, before the pickling check on lines 293–294. If ForkingPickler.dumps raises, the timestamps are already advanced and these tasks won\u0027t be retried until their next full interval, even though they never ran. Consider moving the pickling check above the loop so state is only mutated after we know dispatch will succeed.","commit_id":"21d2efa4ef4ad53def4b2eb4c01d389dadb62d03"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"1065004e36c190cea51bb9ae6784828ee2c156ba","unresolved":false,"context_lines":[{"line_number":282,"context_line":""},{"line_number":283,"context_line":"            LOG.debug(\"Running periodic task %(full_task_name)s (parallel)\","},{"line_number":284,"context_line":"                      {\"full_task_name\": full_task_name})"},{"line_number":285,"context_line":"            self._periodic_last_run[task_name] \u003d _nearest_boundary("},{"line_number":286,"context_line":"                last_run, spacing)"},{"line_number":287,"context_line":"            due_tasks.append((full_task_name, task_name, task))"},{"line_number":288,"context_line":""},{"line_number":289,"context_line":"        if not due_tasks:"},{"line_number":290,"context_line":"            return idle_for"}],"source_content_type":"text/x-python","patch_set":12,"id":"55e7fc12_6fe66689","line":287,"range":{"start_line":285,"start_character":0,"end_line":287,"end_character":63},"in_reply_to":"b59191fe_6ae25c49","updated":"2026-04-15 10:33:09.000000000","message":"Done","commit_id":"21d2efa4ef4ad53def4b2eb4c01d389dadb62d03"}],"oslo_service/tests/backend/threading/test_launcher.py":[{"author":{"_account_id":38752,"name":"Pavlo Kostianov","email":"pkostian@redhat.com","username":"pkostian"},"change_message_id":"32034973fc2358e2c4be5782762ea6b4e841c1a3","unresolved":true,"context_lines":[{"line_number":59,"context_line":"class BaseLauncherTestCase(TestCase):"},{"line_number":60,"context_line":"    def setUp(self):"},{"line_number":61,"context_line":"        super().setUp()"},{"line_number":62,"context_line":"        # Reset ServiceManager singleton for order-independent tests."},{"line_number":63,"context_line":"        cotyledon.ServiceManager._process_runner_already_created \u003d False"},{"line_number":64,"context_line":"        self.conf \u003d cfg.ConfigOpts()"},{"line_number":65,"context_line":"        # Reset ServiceManager singleton between tests"},{"line_number":66,"context_line":"        # This allows creating multiple ServiceManager instances in tests"}],"source_content_type":"text/x-python","patch_set":12,"id":"4573841c_33fec6ae","line":63,"range":{"start_line":62,"start_character":8,"end_line":63,"end_character":72},"updated":"2026-04-13 12:39:41.000000000","message":"The reset duplicates lines 65-67, is there a reason for that?","commit_id":"21d2efa4ef4ad53def4b2eb4c01d389dadb62d03"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"1065004e36c190cea51bb9ae6784828ee2c156ba","unresolved":false,"context_lines":[{"line_number":59,"context_line":"class BaseLauncherTestCase(TestCase):"},{"line_number":60,"context_line":"    def setUp(self):"},{"line_number":61,"context_line":"        super().setUp()"},{"line_number":62,"context_line":"        # Reset ServiceManager singleton for order-independent tests."},{"line_number":63,"context_line":"        cotyledon.ServiceManager._process_runner_already_created \u003d False"},{"line_number":64,"context_line":"        self.conf \u003d cfg.ConfigOpts()"},{"line_number":65,"context_line":"        # Reset ServiceManager singleton between tests"},{"line_number":66,"context_line":"        # This allows creating multiple ServiceManager instances in tests"}],"source_content_type":"text/x-python","patch_set":12,"id":"bfd5eaa3_35ec94ea","line":63,"range":{"start_line":62,"start_character":8,"end_line":63,"end_character":72},"in_reply_to":"4573841c_33fec6ae","updated":"2026-04-15 10:33:09.000000000","message":"Done","commit_id":"21d2efa4ef4ad53def4b2eb4c01d389dadb62d03"}],"releasenotes/notes/run-periodic-tasks-in-parallel-spawn-31469d3375e30a57.yaml":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"e6555345987fe3680af71d0a4fe35faff8587979","unresolved":true,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Added run_periodic_tasks_in_parallel() to run due periodic tasks in"},{"line_number":5,"context_line":"    parallel using a spawn-based process pool. Services that schedule"},{"line_number":6,"context_line":"    periodic work (e.g. via ThreadGroup add_dynamic_timer) can use this"},{"line_number":7,"context_line":"    method to run tasks in parallel. The method is restricted to the"},{"line_number":8,"context_line":"    threading backend. The service instance and context must be picklable"}],"source_content_type":"text/x-yaml","patch_set":5,"id":"0d4557a0_c5b39886","line":5,"range":{"start_line":5,"start_character":13,"end_line":5,"end_character":45},"updated":"2026-02-06 15:58:21.000000000","message":"Let\u0027s remove this point, because the most important point is the parallel mechanism itself. This explains how you implemented it, not what you implemented.","commit_id":"3ae6bb18c956a531a1d0fba27263f1528e025aa6"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"0178f6f83cbd6e8deb2c6f24705c91094e46669c","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Added run_periodic_tasks_in_parallel() to run due periodic tasks in"},{"line_number":5,"context_line":"    parallel using a spawn-based process pool. Services that schedule"},{"line_number":6,"context_line":"    periodic work (e.g. via ThreadGroup add_dynamic_timer) can use this"},{"line_number":7,"context_line":"    method to run tasks in parallel. The method is restricted to the"},{"line_number":8,"context_line":"    threading backend. The service instance and context must be picklable"}],"source_content_type":"text/x-yaml","patch_set":5,"id":"8998c6a2_d693197f","line":5,"range":{"start_line":5,"start_character":13,"end_line":5,"end_character":45},"in_reply_to":"0d4557a0_c5b39886","updated":"2026-02-06 16:15:31.000000000","message":"Done","commit_id":"3ae6bb18c956a531a1d0fba27263f1528e025aa6"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"283587b2ad89a284e9635886ba2bbaacd24a5cf8","unresolved":true,"context_lines":[{"line_number":5,"context_line":"    due periodic tasks concurrently when explicitly requested."},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"    This helper is supported only with the ``threading`` backend and"},{"line_number":8,"context_line":"    requires the service instance and execution context to be picklable."}],"source_content_type":"text/x-yaml","patch_set":11,"id":"f8b247c0_5ccaf4b2","line":8,"range":{"start_line":8,"start_character":17,"end_line":8,"end_character":24},"updated":"2026-03-23 15:14:28.000000000","message":"PeriodicTasks","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"},{"author":{"_account_id":31245,"name":"Daniel Bengtsson","email":"dbengt@redhat.com","username":"damani42"},"change_message_id":"90cd89a181ca2395e780d82c5f49e53f3e601838","unresolved":false,"context_lines":[{"line_number":5,"context_line":"    due periodic tasks concurrently when explicitly requested."},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"    This helper is supported only with the ``threading`` backend and"},{"line_number":8,"context_line":"    requires the service instance and execution context to be picklable."}],"source_content_type":"text/x-yaml","patch_set":11,"id":"4493336c_7249d2ec","line":8,"range":{"start_line":8,"start_character":17,"end_line":8,"end_character":24},"in_reply_to":"f8b247c0_5ccaf4b2","updated":"2026-03-27 13:22:37.000000000","message":"Done","commit_id":"a54082639315fb7cf5b66cf0d629fef24b1af354"}]}
