public IObservable <ResourceEvent <TResource> > GetResource(ResourceStreamType type, TOptions options)
 {
     if (!_sharedInformers.TryGetValue(options, out var sharedInformer))
     {
         var optionLockedMasterInformer = _masterInformer.WithOptions(options);
         sharedInformer = _sharedInformerFactory(optionLockedMasterInformer);
         _sharedInformers.Add(options, sharedInformer);
     }
     return(sharedInformer.GetResource(type));
 }
Пример #2
0
 /// <inheritdoc cref="IKubernetesInformer{TResource}"/>
 public IObservable <ResourceEvent <TResource> > GetResource(ResourceStreamType type) => base.GetResource(type, KubernetesInformerOptions.Default);
Пример #3
0
 public KubernetesInformerEmitter(KubernetesInformer <TResource> parent, KubernetesInformerOptions options, ResourceStreamType type)
 {
     _parent  = parent;
     _options = options;
     _type    = type;
 }
Пример #4
0
 public IObservable <ResourceEvent <TResource> > GetResource(ResourceStreamType type, KubernetesInformerOptions options)
 {
     return(new KubernetesInformerEmitter(this, options, type).GetObservable());
 }
        public IObservable <ResourceEvent <TResource> > GetResource(ResourceStreamType type)
        {
            var childScheduler = new EventLoopScheduler(); // dedicated thread for the child on which all messages are syncrhonized

            return(Observable.Defer(async() =>
            {
                AddSubscriber();
                _logger.LogTrace("Subscriber awaiting cache synchronization before attaching");

                var isCacheSynchronized = await _cacheSynchronized.Task;
                if (!isCacheSynchronized)     // really this only happens if the reset is the master completes before first reset, in which case the downstream subscriber gets nothing
                {
                    return Observable.Empty <ResourceEvent <TResource> >();
                }
                // we use lock to pause any processing of the broadcaster while we're attaching to the stream so proper alignment can be made

                _logger.LogTrace("Subscriber attaching to broadcaster");
                return Observable.Create <ResourceEvent <TResource> >(observer =>
                {
                    var broadcasterAttachment = Disposable.Empty;
                    var cacheSnapshot = _cache.Snapshot();
                    if (type.HasFlag(ResourceStreamType.List))
                    {
                        _logger.LogTrace($"Flushing contents of cache version {cacheSnapshot.Version}");
                        _cache.Values
                        .ToReset(type == ResourceStreamType.ListWatch)
                        .ToObservable()
                        .Concat(Observable.Never <ResourceEvent <TResource> >())
                        .ObserveOn(Scheduler.Immediate)
                        .Subscribe(observer);
                    }

                    if (type.HasFlag(ResourceStreamType.Watch))
                    {
                        broadcasterAttachment = _masterObservable
                                                // we could be ahead of broadcaster because we initialized from cache which gets updated before the message are sent to broadcaster
                                                // this logic realigns us at the correct point with the broadcaster
                                                .Do(x => _logger.LogTrace($"Received from broadcaster {x}"))
                                                .SkipWhile(x => x.MessageNumber <= cacheSnapshot.Version)
                                                .Select(x => x.Value)
                                                .Do(x => _logger.LogTrace($"Aligned with broadcaster {x}"))
                                                .SubscribeOn(_masterScheduler)
                                                .ObserveOn(childScheduler)
                                                .Subscribe(observer, () =>
                        {
                            _logger.LogTrace("Child OnComplete");
                            RemoveSubscriber();
                        });
                    }
                    else
                    {
                        observer.OnCompleted();
                    }

                    // let broadcaster know we're done attaching to stream so it can resume it's regular work
                    _logger.LogTrace("Finished attaching to stream - signalling to resume");
                    lock (_lock)
                    {
                        _waitingSubscribers.Signal();
                    }

                    return broadcasterAttachment;
                })
                .ObserveOn(childScheduler)
                .SubscribeOn(childScheduler);
            })
                   .SubscribeOn(childScheduler) // ensures that when we attach master observer it's done on child thread, as we plan on awaiting cache synchronization
                   .Do(_ => _logger.LogTrace($"Shared informer out: {_}")));
        }
Пример #6
0
 public IObservable <ResourceEvent <TResource> > GetResource(ResourceStreamType type) => _informer.GetResource(type, _options);