@@ -186,8 +186,44 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
186186 void Handle (TEvConsole::TEvGetNodeLabelsRequest::TPtr &ev);
187187 void Handle (TEvConsole::TEvFetchStartupConfigRequest::TPtr &ev);
188188 void Handle (TEvConsole::TEvGetNodeConfigurationVersionRequest::TPtr &ev);
189+ void Handle (TEvConfigsDispatcher::TEvGetStateRequest::TPtr &ev);
190+ void Handle (TEvConfigsDispatcher::TEvGetStorageYamlRequest::TPtr &ev);
189191
190192 void ReplyMonJson (TActorId mailbox);
193+
194+ EConfigSource DetermineConfigSource () const {
195+ if (auto it = Labels.find (" config_source" ); it != Labels.end ()) {
196+ if (it->second == " seed_nodes" ) {
197+ return EConfigSource::SeedNodes;
198+ }
199+ }
200+ return EConfigSource::DynamicConfig;
201+ }
202+
203+ TConfigsDispatcherState GetState () const {
204+ TConfigsDispatcherState state;
205+
206+ auto configSource = DetermineConfigSource ();
207+ state.ConfigSource = configSource;
208+
209+ if (auto it = Labels.find (" config_source" ); it != Labels.end ()) {
210+ state.ConfigSourceLabel = it->second ;
211+ }
212+
213+ if (auto it = Labels.find (" configuration_version" ); it != Labels.end ()) {
214+ state.ConfigurationVersion = it->second ;
215+ }
216+
217+ state.HasStorageYaml = !StartupStorageYaml.empty ();
218+ state.StorageYamlSize = StartupStorageYaml.size ();
219+ state.YamlConfigEnabled = YamlConfigEnabled;
220+ state.SubscriptionsCount = SubscriptionsByKinds.size ();
221+ state.LastReplayUsedSeedNodesPath = LastReplayUsedSeedNodesPath;
222+ state.LastReplayUsedDynamicConfigPath = LastReplayUsedDynamicConfigPath;
223+ state.Labels = Labels;
224+
225+ return state;
226+ }
191227
192228 STATEFN (StateInit)
193229 {
@@ -203,6 +239,8 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
203239 hFuncTraced (TEvConfigsDispatcher::TEvGetConfigRequest, Handle);
204240 hFuncTraced (TEvConfigsDispatcher::TEvSetConfigSubscriptionRequest, Handle);
205241 hFuncTraced (TEvConfigsDispatcher::TEvRemoveConfigSubscriptionRequest, Handle);
242+ hFuncTraced (TEvConfigsDispatcher::TEvGetStateRequest, Handle);
243+ hFuncTraced (TEvConfigsDispatcher::TEvGetStorageYamlRequest, Handle);
206244 // Resolve
207245 hFunc (TEvConsole::TEvGetNodeLabelsRequest, Handle);
208246 hFunc (TEvConsole::TEvFetchStartupConfigRequest, Handle);
@@ -228,6 +266,8 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
228266 hFuncTraced (TEvConfigsDispatcher::TEvRemoveConfigSubscriptionRequest, Handle);
229267 hFuncTraced (TEvConsole::TEvConfigNotificationResponse, Handle);
230268 IgnoreFunc (TEvConfigsDispatcher::TEvSetConfigSubscriptionResponse);
269+ hFuncTraced (TEvConfigsDispatcher::TEvGetStateRequest, Handle);
270+ hFuncTraced (TEvConfigsDispatcher::TEvGetStorageYamlRequest, Handle);
231271 // Resolve
232272 hFunc (TEvConsole::TEvGetNodeLabelsRequest, Handle);
233273 hFunc (TEvConsole::TEvFetchStartupConfigRequest, Handle);
@@ -249,6 +289,7 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
249289 const NKikimrConfig::TAppConfig BaseConfig;
250290 NKikimrConfig::TAppConfig CurrentConfig;
251291 const TString StartupConfigYaml;
292+ const TString StartupStorageYaml;
252293 NKikimrConfig::TAppConfig CandidateStartupConfig;
253294 bool StartupConfigProcessError = false ;
254295 bool StartupConfigProcessDiff = false ;
@@ -263,6 +304,10 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
263304 TVector<TActorId> HttpRequests;
264305 TActorId CommonSubscriptionClient;
265306 TDeque<TAutoPtr<IEventHandle>> EventsQueue;
307+
308+ // Observability: Track which replay path was used
309+ bool LastReplayUsedSeedNodesPath = false ;
310+ bool LastReplayUsedDynamicConfigPath = false ;
266311
267312 THashMap<TActorId, TSubscription::TPtr> SubscriptionsBySubscriber;
268313 THashMap<TDynBitMap, TSubscription::TPtr> SubscriptionsByKinds;
@@ -285,6 +330,7 @@ TConfigsDispatcher::TConfigsDispatcher(const TConfigsDispatcherInitInfo& initInf
285330 , BaseConfig(initInfo.InitialConfig)
286331 , CurrentConfig(initInfo.InitialConfig)
287332 , StartupConfigYaml(initInfo.StartupConfigYaml)
333+ , StartupStorageYaml(initInfo.StartupStorageYaml)
288334 , CandidateStartupConfig(initInfo.InitialConfig)
289335 , DebugInfo(initInfo.DebugInfo)
290336 , RecordedInitialConfiguratorDeps(std::move(initInfo.RecordedInitialConfiguratorDeps))
@@ -442,6 +488,20 @@ void TConfigsDispatcher::ReplyMonJson(TActorId mailbox) {
442488 response.InsertValue (" yaml_config" , MainYamlConfig);
443489 response.InsertValue (" resolved_json_config" , NJson::ReadJsonFastTree (ResolvedJsonConfig, true ));
444490 response.InsertValue (" current_json_config" , NJson::ReadJsonFastTree (NProtobufJson::Proto2Json (CurrentConfig, NYamlConfig::GetProto2JsonConfig ()), true ));
491+
492+ auto state = GetState ();
493+ if (auto it = Labels.find (" config_source" ); it != Labels.end ()) {
494+ response.InsertValue (" config_source" , it->second );
495+ }
496+ if (auto it = Labels.find (" configuration_version" ); it != Labels.end ()) {
497+ response.InsertValue (" configuration_version" , it->second );
498+ }
499+ response.InsertValue (" has_storage_yaml" , state.HasStorageYaml );
500+ if (state.HasStorageYaml ) {
501+ response.InsertValue (" storage_yaml_size" , static_cast <i64 >(state.StorageYamlSize ));
502+ }
503+ response.InsertValue (" last_replay_seed_nodes" , state.LastReplayUsedSeedNodesPath );
504+ response.InsertValue (" last_replay_dynamic_config" , state.LastReplayUsedDynamicConfigPath );
445505
446506 if (DebugInfo) {
447507 // TODO: write custom json serializer for security fields
@@ -652,6 +712,19 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev)
652712 : s == &TThis::StateInit ? " StateInit"
653713 : " Unknown" ) << Endl;
654714 str << " YamlConfigEnabled: " << YamlConfigEnabled << Endl;
715+
716+ str << Endl << " === Configuration Source ===" << Endl;
717+ auto state = GetState ();
718+ str << state.ToDebugString () << Endl;
719+ if (LastReplayUsedSeedNodesPath) {
720+ str << " Last Replay Path: Seed Nodes (ConfigClient)" << Endl;
721+ } else if (LastReplayUsedDynamicConfigPath) {
722+ str << " Last Replay Path: Dynamic Config (DynConfigClient)" << Endl;
723+ } else {
724+ str << " Last Replay Path: Not yet executed" << Endl;
725+ }
726+ str << Endl;
727+
655728 str << " Subscriptions: " << Endl;
656729 for (auto &[kinds, subscription] : SubscriptionsByKinds) {
657730 str << " - Kinds: " << KindsToString (kinds) << Endl
@@ -759,6 +832,34 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev)
759832 }
760833 }
761834 str << " <br />" << Endl;
835+ COLLAPSED_REF_CONTENT (" storage-yaml-config" , " Storage YAML Config (Seed Nodes)" ) {
836+ if (!StartupStorageYaml.empty ()) {
837+ DIV () {
838+ TAG (TH5) {
839+ str << " Startup Storage Config (from seed nodes)" << Endl;
840+ }
841+ TAG_CLASS_STYLE (TDiv, " configs-dispatcher" , " padding: 0 12px;" ) {
842+ TAG_ATTRS (TDiv, {{" class" , " yaml-sticky-btn-wrap fold-yaml-config yaml-btn-3" }, {" title" , " fold" }}) {
843+ DIV_CLASS (" yaml-sticky-btn" ) { }
844+ }
845+ TAG_ATTRS (TDiv, {{" class" , " yaml-sticky-btn-wrap unfold-yaml-config yaml-btn-2" }, {" title" , " unfold" }}) {
846+ DIV_CLASS (" yaml-sticky-btn" ) { }
847+ }
848+ TAG_ATTRS (TDiv, {{" class" , " yaml-sticky-btn-wrap copy-yaml-config yaml-btn-1" }, {" title" , " copy" }}) {
849+ DIV_CLASS (" yaml-sticky-btn" ) { }
850+ }
851+ DIV_CLASS (" yaml-config-item" ) {
852+ str << StartupStorageYaml;
853+ }
854+ }
855+ }
856+ } else {
857+ str << " <div class=\" alert alert-info\" role=\" alert\" >" << Endl;
858+ str << " No storage config available. This is normal for non-seed-nodes initialization." << Endl;
859+ str << " </div>" << Endl;
860+ }
861+ }
862+ str << " <br />" << Endl;
762863 COLLAPSED_REF_CONTENT (" resolved-yaml-config" , " Resolved YAML config" ) {
763864 TAG_CLASS_STYLE (TDiv, " configs-dispatcher" , " padding: 0 12px;" ) {
764865 TAG_ATTRS (TDiv, {{" class" , " yaml-sticky-btn-wrap fold-yaml-config yaml-btn-3" }, {" id" , " fold-resolved-yaml-config" }, {" title" , " fold" }}) {
@@ -818,9 +919,9 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev)
818919
819920class TConfigurationResult
820921 : public IConfigurationResult
922+ , public IStorageConfigResult
821923{
822924public:
823- // TODO make ref
824925 const NKikimrConfig::TAppConfig& GetConfig () const override {
825926 return Config;
826927 }
@@ -829,10 +930,6 @@ class TConfigurationResult
829930 return !MainYamlConfig.empty ();
830931 }
831932
832- const TString& GetMainYamlConfig () const override {
833- return MainYamlConfig;
834- }
835-
836933 TMap<ui64, TString> GetVolatileYamlConfigs () const override {
837934 return VolatileYamlConfigs;
838935 }
@@ -845,10 +942,24 @@ class TConfigurationResult
845942 return DatabaseYamlConfig;
846943 }
847944
945+ const TString& GetStorageYamlConfig () const override {
946+ return StorageYamlConfig;
947+ }
948+
949+ const TString& GetSourceAddress () const override {
950+ return SourceAddress;
951+ }
952+
953+ const TString& GetMainYamlConfig () const override {
954+ return MainYamlConfig;
955+ }
956+
848957 NKikimrConfig::TAppConfig Config;
849958 TString MainYamlConfig;
850959 TMap<ui64, TString> VolatileYamlConfigs;
851960 TString DatabaseYamlConfig;
961+ TString StorageYamlConfig;
962+ TString SourceAddress;
852963};
853964
854965void TConfigsDispatcher::UpdateCandidateStartupConfig (TEvConsole::TEvConfigSubscriptionNotification::TPtr &ev)
@@ -864,16 +975,41 @@ try {
864975
865976 auto &rec = ev->Get ()->Record ;
866977
867- auto dcClient = std::make_unique<TDynConfigClientMock>();
868978 auto configs = std::make_shared<TConfigurationResult>();
869- dcClient->SavedResult = configs;
870979 configs->Config = rec.GetRawConsoleConfig ();
871980 configs->MainYamlConfig = rec.GetMainYamlConfig ();
872981 if (rec.HasDatabaseYamlConfig ()) {
873982 configs->DatabaseYamlConfig = rec.GetDatabaseYamlConfig ();
874983 }
875984 // TODO volatile
876- RecordedInitialConfiguratorDeps->DynConfigClient = std::move (dcClient);
985+
986+ auto configSource = DetermineConfigSource ();
987+
988+ LastReplayUsedSeedNodesPath = false ;
989+ LastReplayUsedDynamicConfigPath = false ;
990+
991+ switch (configSource) {
992+ case EConfigSource::SeedNodes:
993+ configs->StorageYamlConfig = StartupStorageYaml;
994+ {
995+ auto configClient = std::make_unique<TConfigClientMock>();
996+ configClient->SavedResult = configs;
997+ RecordedInitialConfiguratorDeps->ConfigClient = std::move (configClient);
998+ }
999+ LastReplayUsedSeedNodesPath = true ;
1000+ break ;
1001+
1002+ case EConfigSource::DynamicConfig:
1003+ case EConfigSource::Unknown:
1004+ {
1005+ auto dcClient = std::make_unique<TDynConfigClientMock>();
1006+ dcClient->SavedResult = configs;
1007+ RecordedInitialConfiguratorDeps->DynConfigClient = std::move (dcClient);
1008+ }
1009+ LastReplayUsedDynamicConfigPath = true ;
1010+ break ;
1011+ }
1012+
8771013 auto deps = RecordedInitialConfiguratorDeps->GetDeps ();
8781014 NConfig::TInitialConfigurator initCfg (deps);
8791015
@@ -1051,9 +1187,11 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvConfigSubscriptionNotification::T
10511187 }
10521188
10531189 if (CurrentStateFunc () == &TThis::StateInit) {
1190+ BLOG_D (" Handle TEvConfigSubscriptionNotification: transitioning to StateWork" );
10541191 Become (&TThis::StateWork);
10551192 ProcessEnqueuedEvents ();
10561193 }
1194+ BLOG_D (" Handle TEvConfigSubscriptionNotification: exit" );
10571195}
10581196
10591197void TConfigsDispatcher::UpdateYamlVersion (const TSubscription::TPtr &subscription) const
@@ -1295,6 +1433,15 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvGetNodeConfigurationVersionReques
12951433 Send (ev->Sender , response.release ());
12961434}
12971435
1436+ void TConfigsDispatcher::Handle (TEvConfigsDispatcher::TEvGetStateRequest::TPtr &ev) {
1437+ auto state = GetState ();
1438+ Send (ev->Sender , new TEvConfigsDispatcher::TEvGetStateResponse (std::move (state)));
1439+ }
1440+
1441+ void TConfigsDispatcher::Handle (TEvConfigsDispatcher::TEvGetStorageYamlRequest::TPtr &ev) {
1442+ Send (ev->Sender , new TEvConfigsDispatcher::TEvGetStorageYamlResponse (StartupStorageYaml));
1443+ }
1444+
12981445IActor *CreateConfigsDispatcher (const TConfigsDispatcherInitInfo& initInfo) {
12991446 return new TConfigsDispatcher (initInfo);
13001447}
0 commit comments