diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp index e66f42fcf032d2..e47e0f9fd9d983 100644 --- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp +++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp @@ -364,8 +364,7 @@ class OpCredsFabricTableDelegate : public chip::FabricTable::Delegate static_cast(fabricIndex)); fabricListChanged(); - // The Leave event SHOULD be emitted by a Node prior to permanently - // leaving the Fabric. + // The Leave event SHOULD be emitted by a Node prior to permanently leaving the Fabric. for (auto endpoint : EnabledEndpointsWithServerCluster(Basic::Id)) { // If Basic cluster is implemented on this endpoint @@ -377,6 +376,26 @@ class OpCredsFabricTableDelegate : public chip::FabricTable::Delegate ChipLogError(Zcl, "OpCredsFabricTableDelegate: Failed to record Leave event"); } } + + // Try to send the queued events as soon as possible. If the just emitted leave event won't + // be sent this time, it will likely not be delivered at all for the following reasons: + // - removing the fabric expires all associated ReadHandlers, so all subscriptions to + // the leave event will be cancelled. + // - removing the fabric removes all associated access control entries, so generating + // subsequent reports containing the leave event will fail the access control check. + InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleUrgentEventDeliverySync(); + EventManagement::GetInstance().FabricRemoved(fabricIndex); + + // Remove access control entries in reverse order (it could be any order, but reverse order + // will cause less churn in persistent storage). + size_t aclCount = 0; + if (Access::GetAccessControl().GetEntryCount(fabricIndex, aclCount) == CHIP_NO_ERROR) + { + while (aclCount) + { + (void) Access::GetAccessControl().DeleteEntry(nullptr, fabricIndex, --aclCount); + } + } } // Gets called when a fabric is loaded into the FabricTable from storage diff --git a/src/app/server/Server.h b/src/app/server/Server.h index b31e8896b3ec4f..68b8cc92a8f303 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -333,21 +333,6 @@ class Server static_cast(fabricIndex), err.Format()); } } - - { - // Remove access control entries in reverse order. (It could be - // any order, but reverse order will cause less churn in - // persistent storage.) - size_t count = 0; - if (Access::GetAccessControl().GetEntryCount(fabricIndex, count) == CHIP_NO_ERROR) - { - while (count) - { - (void) Access::GetAccessControl().DeleteEntry(nullptr, fabricIndex, --count); - } - } - } - app::EventManagement::GetInstance().FabricRemoved(fabricIndex); }; void OnFabricRetrievedFromStorage(FabricTable & fabricTable, FabricIndex fabricIndex) override