public void CopyTo(ConsulDependencies other) { other.Keys.UnionWith(Keys); other.ConfigurationKeys.UnionWith(ConfigurationKeys); other.KeyPrefixes.UnionWith(KeyPrefixes); other.Services.UnionWith(Services); }
public async Task <ConsulState> GetDependenciesAsync(ConsulDependencies dependencies) { var serviceTasks = dependencies.Services.Select(GetServiceAsync); var keyTasks = dependencies.Keys.Select(GetKeyAsync); var configKeyTasks = dependencies.ConfigurationKeys.Select(GetKeyAsync); var keyRecursiveTasks = dependencies.KeyPrefixes.Select(GetKeyRecursiveAsync); await Task.WhenAll(serviceTasks.Cast <Task>().Concat(keyTasks).Concat(configKeyTasks).Concat(keyRecursiveTasks)); var services = serviceTasks.Select(t => t.Result) .Where(s => s != null) .ToImmutableDictionary(s => s.Name); var keys = new KeyValueStore(keyTasks .Select(t => t.Result) .Where(k => k != null) .Concat(configKeyTasks.Select(x => x.Result)) .Concat(keyRecursiveTasks.SelectMany(t => t.Result))); var missingKeyPrefixes = dependencies.KeyPrefixes .Where(prefix => !keys.ContainsKeyStartingWith(prefix)) .ToImmutableHashSet(); return(new ConsulState(services, keys, missingKeyPrefixes)); }
public IObservable <ConsulState> ObserveDependencies(ConsulDependencies dependencies) { var consulState = new ConsulState(); var updateMutex = new object(); void WrapUpdate(string operationName, Action <EventContext> tryUpdate) { var eventContext = new EventContext("ConsulRx.ConsulState", operationName); try { lock (updateMutex) { tryUpdate(eventContext); } } catch (Exception ex) { eventContext.IncludeException(ex); throw; } finally { eventContext.Dispose(); } } var consulStateObservable = Observable.Create <ConsulState>(o => { var compositeDisposable = new CompositeDisposable { this.ObserveServices(dependencies.Services) .Select(services => services.ToService()) .Subscribe(service => { WrapUpdate("UpdateService", eventContext => { eventContext["ServiceName"] = service.Name; bool alreadyExisted = consulState.ContainsService(service.Name); if (consulState.TryUpdateService(service, out var updatedState)) { eventContext["UpdateType"] = alreadyExisted ? "Update" : "Add"; consulState = updatedState; o.OnNext(consulState); } else { eventContext["UpdateType"] = "Noop"; } }); }, o.OnError), this.ObserveKeys(dependencies.Keys) .Select(kv => kv.ToKeyValueNode()) .Subscribe(kvNode => { WrapUpdate("UpdateKey", eventContext => { eventContext["Key"] = kvNode.FullKey; eventContext["Value"] = kvNode.Value; bool alreadyExisted = consulState.ContainsKey(kvNode.FullKey); if (consulState.TryUpdateKVNode(kvNode, out var updatedState)) { eventContext["UpdateType"] = alreadyExisted ? "Update" : "Add"; consulState = updatedState; o.OnNext(consulState); } else { eventContext["UpdateType"] = "Noop"; } }); }, o.OnError), this.ObserveKeysRecursive(dependencies.KeyPrefixes) .Subscribe(kv => { WrapUpdate("UpdateKeys", eventContext => { eventContext["KeyPrefix"] = kv.KeyPrefix; eventContext["ChildKeyCount"] = kv.Result.Response?.Length ?? 0; if (kv.Result.Response == null || !kv.Result.Response.Any()) { if (consulState.TryMarkKeyPrefixAsMissingOrEmpty(kv.KeyPrefix, out var updatedState) ) { eventContext["UpdateType"] = "MarkAsMissing"; consulState = updatedState; o.OnNext(consulState); } else { eventContext["UpdateType"] = "Noop"; } } else { var kvNodes = kv.ToKeyValueNodes(); bool alreadyExisted = consulState.ContainsKeyStartingWith(kv.KeyPrefix); if (consulState.TryUpdateKVNodes(kvNodes, out var updatedState)) { eventContext["UpdateType"] = alreadyExisted ? "Update" : "Add"; consulState = updatedState; o.OnNext(consulState); } else { eventContext["UpdateType"] = "Noop"; } } }); }, o.OnError) }; return(compositeDisposable); }); return(consulStateObservable.Where(s => s.SatisfiesAll(dependencies))); }
public bool SatisfiesAll(ConsulDependencies consulDependencies) { return(consulDependencies.Services.IsSubsetOf(_services.Keys) && consulDependencies.Keys.IsSubsetOf(KVStore.Select(s => s.FullKey)) && consulDependencies.KeyPrefixes.All(p => KVStore.Any(k => k.FullKey.StartsWith(p)) || _missingKeyPrefixes.Contains(p))); }