)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"e89e355cd5e6fb2a023b31dc18364bb9570b093f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"3053e656_f6c5c12a","updated":"2026-08-12 12:16:01.000000000","message":"I think we need to fix the periodics overwrite, not patch around it. The existing pattern is to extract a normal method with the actual implementation and override only it. Then the periodic jobs stays only in the base class.","commit_id":"6fb097fc5a67b4f3cccda94702398419c909d29e"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"7924b38c8366671a6d8b03b4f881137678af09fd","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"642e5ce1_a6f407e7","updated":"2026-08-13 03:31:37.000000000","message":"more testing / review needed","commit_id":"4ae4c644496491141a84175c833d21b0ce96a9e6"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"c33317e0bc8fa45e1d260d6ea89b289338bbdc42","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"03727581_4bebadd9","updated":"2026-08-13 11:14:48.000000000","message":"Thank you for your review Dmitry, pushing new revision of the patch.","commit_id":"282311b0d2a21d999345a2d19c9f1b6b08a8c916"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"a90696ab19e3598f42bf5bc0f830f6cfcbba51ec","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"9552dd72_77964955","updated":"2026-08-17 04:35:48.000000000","message":"Thank you, Dmitry, pushed a new, reworked and simplified revision.","commit_id":"5fe5a9b54227aed5c2210582d90967b04cf85595"}],"ironic/conductor/base_manager.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"a86f7fee539f24ab704590f99cd4ff6b5a2a23c0","unresolved":true,"context_lines":[{"line_number":382,"context_line":"        # instance.  Maps func id to index in periodic_task_callables so"},{"line_number":383,"context_line":"        # the entry can be replaced if the defining class is encountered"},{"line_number":384,"context_line":"        # after a subclass."},{"line_number":385,"context_line":"        seen_funcs \u003d {}"},{"line_number":386,"context_line":""},{"line_number":387,"context_line":"        def _collect_from(obj, args):"},{"line_number":388,"context_line":"            \"\"\"Collect tasks from the given object."}],"source_content_type":"text/x-python","patch_set":6,"id":"47017145_de1cfe58","line":385,"updated":"2026-08-13 08:50:35.000000000","message":"Isn\u0027t seen_funcs local to each `obj`?","commit_id":"4ae4c644496491141a84175c833d21b0ce96a9e6"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"c33317e0bc8fa45e1d260d6ea89b289338bbdc42","unresolved":true,"context_lines":[{"line_number":382,"context_line":"        # instance.  Maps func id to index in periodic_task_callables so"},{"line_number":383,"context_line":"        # the entry can be replaced if the defining class is encountered"},{"line_number":384,"context_line":"        # after a subclass."},{"line_number":385,"context_line":"        seen_funcs \u003d {}"},{"line_number":386,"context_line":""},{"line_number":387,"context_line":"        def _collect_from(obj, args):"},{"line_number":388,"context_line":"            \"\"\"Collect tasks from the given object."}],"source_content_type":"text/x-python","patch_set":6,"id":"7fe6dd4c_3271734a","line":385,"in_reply_to":"47017145_de1cfe58","updated":"2026-08-13 11:14:48.000000000","message":"I asked Claude about this: \nseen_funcs is a closure variable, same as periodic_task_callables and periodic_task_classes — all three are declared in _collect_periodic_tasks and captured by _collect_from. Kept handling of all three consistent - let me know if this is ok?","commit_id":"4ae4c644496491141a84175c833d21b0ce96a9e6"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"a86f7fee539f24ab704590f99cd4ff6b5a2a23c0","unresolved":true,"context_lines":[{"line_number":391,"context_line":"            :param args: a tuple of arguments to pass to tasks."},{"line_number":392,"context_line":"            \"\"\""},{"line_number":393,"context_line":"            if obj and obj.__class__ not in periodic_task_classes:"},{"line_number":394,"context_line":"                for name, member in inspect.getmembers(obj):"},{"line_number":395,"context_line":"                    if periodics.is_periodic(member):"},{"line_number":396,"context_line":"                        func \u003d getattr(member, \u0027__func__\u0027, member)"},{"line_number":397,"context_line":"                        func_id \u003d id(func)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9aae174a_bfd74393","line":394,"updated":"2026-08-13 08:50:35.000000000","message":"A potentially less confusing way to solve this would be to drop `getmembers` in favour of something along the lines of\n\n```\nfor cls in inspect.getmro(obj.__class__):\n  for name, member in cls.__dict__.items():\n```\n\nThen you don\u0027t need to track the index because MRO already provides classes in the right order. You only need to avoid overwriting already recorded members for `obj`.","commit_id":"4ae4c644496491141a84175c833d21b0ce96a9e6"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"c33317e0bc8fa45e1d260d6ea89b289338bbdc42","unresolved":false,"context_lines":[{"line_number":391,"context_line":"            :param args: a tuple of arguments to pass to tasks."},{"line_number":392,"context_line":"            \"\"\""},{"line_number":393,"context_line":"            if obj and obj.__class__ not in periodic_task_classes:"},{"line_number":394,"context_line":"                for name, member in inspect.getmembers(obj):"},{"line_number":395,"context_line":"                    if periodics.is_periodic(member):"},{"line_number":396,"context_line":"                        func \u003d getattr(member, \u0027__func__\u0027, member)"},{"line_number":397,"context_line":"                        func_id \u003d id(func)"}],"source_content_type":"text/x-python","patch_set":6,"id":"b1575045_34a4a0bb","line":394,"in_reply_to":"9aae174a_bfd74393","updated":"2026-08-13 11:14:48.000000000","message":"Thank you for your suggestion, applied.","commit_id":"4ae4c644496491141a84175c833d21b0ce96a9e6"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"2c5a2de8081fb48737e68f5b609d8c6378ccae04","unresolved":true,"context_lines":[{"line_number":408,"context_line":"                            and periodics.is_periodic(member):"},{"line_number":409,"context_line":"                        seen_names.add(name)"},{"line_number":410,"context_line":"                        func \u003d getattr(member, \u0027__func__\u0027, member)"},{"line_number":411,"context_line":"                        if id(func) in seen_funcs:"},{"line_number":412,"context_line":"                            LOG.debug("},{"line_number":413,"context_line":"                                \u0027Skipping inherited periodic \u0027"},{"line_number":414,"context_line":"                                \u0027task %(owner)s.%(member)s\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"a9f2bd6e_4556894c","line":411,"updated":"2026-08-13 11:52:18.000000000","message":"The whole point of using MRO is to avoid seen_funcs entirely, because every object will only register the version of a periodic that comes from the \"deepest\" class.","commit_id":"282311b0d2a21d999345a2d19c9f1b6b08a8c916"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"a90696ab19e3598f42bf5bc0f830f6cfcbba51ec","unresolved":true,"context_lines":[{"line_number":408,"context_line":"                            and periodics.is_periodic(member):"},{"line_number":409,"context_line":"                        seen_names.add(name)"},{"line_number":410,"context_line":"                        func \u003d getattr(member, \u0027__func__\u0027, member)"},{"line_number":411,"context_line":"                        if id(func) in seen_funcs:"},{"line_number":412,"context_line":"                            LOG.debug("},{"line_number":413,"context_line":"                                \u0027Skipping inherited periodic \u0027"},{"line_number":414,"context_line":"                                \u0027task %(owner)s.%(member)s\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"68540dab_b507c033","line":411,"in_reply_to":"02c9216b_4db95575","updated":"2026-08-17 04:35:48.000000000","message":"This was a brilliant hint, following this turns a monster-patch to a one-liner. Let me know your thoughts about current version, I will try get it lab-tested.","commit_id":"282311b0d2a21d999345a2d19c9f1b6b08a8c916"},{"author":{"_account_id":32177,"name":"Jacob Anders","email":"jacob-anders-dev@proton.me","username":"janders"},"change_message_id":"3c0994a84c226d03954a33f666b17beeb67ad629","unresolved":true,"context_lines":[{"line_number":408,"context_line":"                            and periodics.is_periodic(member):"},{"line_number":409,"context_line":"                        seen_names.add(name)"},{"line_number":410,"context_line":"                        func \u003d getattr(member, \u0027__func__\u0027, member)"},{"line_number":411,"context_line":"                        if id(func) in seen_funcs:"},{"line_number":412,"context_line":"                            LOG.debug("},{"line_number":413,"context_line":"                                \u0027Skipping inherited periodic \u0027"},{"line_number":414,"context_line":"                                \u0027task %(owner)s.%(member)s\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"02c9216b_4db95575","line":411,"in_reply_to":"82d2e300_59aecf9a","updated":"2026-08-13 12:49:27.000000000","message":"I will think about it a bit more, thank you for the pointer.","commit_id":"282311b0d2a21d999345a2d19c9f1b6b08a8c916"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6c8fb0df648be1b8c34e86a309dcf87226bbd7f4","unresolved":true,"context_lines":[{"line_number":408,"context_line":"                            and periodics.is_periodic(member):"},{"line_number":409,"context_line":"                        seen_names.add(name)"},{"line_number":410,"context_line":"                        func \u003d getattr(member, \u0027__func__\u0027, member)"},{"line_number":411,"context_line":"                        if id(func) in seen_funcs:"},{"line_number":412,"context_line":"                            LOG.debug("},{"line_number":413,"context_line":"                                \u0027Skipping inherited periodic \u0027"},{"line_number":414,"context_line":"                                \u0027task %(owner)s.%(member)s\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"82d2e300_59aecf9a","line":411,"in_reply_to":"a9f2bd6e_4556894c","updated":"2026-08-13 11:56:07.000000000","message":"I\u0027m now wondering if this approach even fixes your issue. If you have both Redfish and iDrac drivers enabled, you **need** to have two periodic tasks. And if the Redfish one catches both Redfish and iDRAC nodes, you have a bit of a problem.","commit_id":"282311b0d2a21d999345a2d19c9f1b6b08a8c916"}],"ironic/conductor/periodics.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"0862bca9d3838d23764597e79f0e8cf484d3891a","unresolved":true,"context_lines":[{"line_number":212,"context_line":"                            # matching keeps the node sets disjoint and"},{"line_number":213,"context_line":"                            # ensures each node is handled by its own"},{"line_number":214,"context_line":"                            # implementation."},{"line_number":215,"context_line":"                            if type(impl) is not type(self):"},{"line_number":216,"context_line":"                                continue"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":"                        result \u003d func(self, task, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":9,"id":"66b44503_9c6ac439","line":215,"updated":"2026-08-17 11:30:26.000000000","message":"Will it work when the parent version is not overridden in the child class?","commit_id":"5fe5a9b54227aed5c2210582d90967b04cf85595"}]}
