public PartitionSupervisorFactory(
            IChangeFeedObserverFactory observerFactory,
            ILeaseManager leaseManager,
            ILeaseCheckpointer leaseCheckpointer,
            ICheckpointPartitionProcessorFactory partitionProcessorFactory,
            ChangeFeedProcessorOptions options)
        {
            if (observerFactory == null)
            {
                throw new ArgumentNullException(nameof(observerFactory));
            }
            if (leaseManager == null)
            {
                throw new ArgumentNullException(nameof(leaseManager));
            }
            if (leaseCheckpointer == null)
            {
                throw new ArgumentNullException(nameof(leaseCheckpointer));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (partitionProcessorFactory == null)
            {
                throw new ArgumentNullException(nameof(partitionProcessorFactory));
            }

            this.observerFactory            = observerFactory;
            this.leaseManager               = leaseManager;
            this.leaseCheckpointer          = leaseCheckpointer;
            this.changeFeedProcessorOptions = options;
            this.partitionProcessorFactory  = partitionProcessorFactory;
        }
Beispiel #2
0
        private async Task <IPartitionManager> BuildPartitionManagerAsync(ILeaseManager leaseManager)
        {
            this.leaseDocumentClient = this.leaseDocumentClient ?? this.leaseCollectionLocation.CreateDocumentClient();

            DocumentCollection leaseCollection = await this.leaseDocumentClient.GetDocumentCollectionAsync(this.leaseCollectionLocation).ConfigureAwait(false);

            string leaseStoreCollectionLink = leaseCollection.SelfLink;

            string collectionSelfLink       = this.feedCollectionLocation.GetCollectionSelfLink();
            var    factory                  = new CheckpointerObserverFactory(this.observerFactory, this.changeFeedProcessorOptions.CheckpointFrequency);
            var    synchronizer             = new PartitionSynchronizer(this.feedDocumentClient, collectionSelfLink, leaseManager, this.changeFeedProcessorOptions.DegreeOfParallelism, this.changeFeedProcessorOptions.QueryPartitionsMaxBatchSize);
            var    leaseStore               = new LeaseStore(this.leaseDocumentClient, this.leaseCollectionLocation, this.GetLeasePrefix(), leaseStoreCollectionLink);
            var    bootstrapper             = new Bootstrapper(synchronizer, leaseStore, this.lockTime, this.sleepTime);
            var    partitionObserverFactory = new PartitionSupervisorFactory(
                factory,
                leaseManager,
                this.partitionProcessorFactory ?? new PartitionProcessorFactory(this.feedDocumentClient, this.changeFeedProcessorOptions, leaseManager, collectionSelfLink),
                this.changeFeedProcessorOptions);

            var partitionController = new PartitionController(leaseManager, partitionObserverFactory, synchronizer);

            if (this.loadBalancingStrategy == null)
            {
                this.loadBalancingStrategy = new EqualPartitionsBalancingStrategy(this.hostName, this.changeFeedProcessorOptions.MinPartitionCount, this.changeFeedProcessorOptions.MaxPartitionCount, this.changeFeedProcessorOptions.LeaseExpirationInterval);
            }

            var partitionLoadBalancer = new PartitionLoadBalancer(partitionController, leaseManager, this.loadBalancingStrategy, this.changeFeedProcessorOptions.LeaseAcquireInterval);

            return(new PartitionManager(bootstrapper, partitionController, partitionLoadBalancer));
        }
Beispiel #3
0
        /// <summary>
        /// Create a new host to process events from an Event Hub with provided <see cref="TokenProvider"/>
        /// </summary>
        /// <param name="hostName">Name of the processor host. MUST BE UNIQUE. Strongly recommend including a Guid to ensure uniqueness.</param>
        /// <param name="endpointAddress">Fully qualified domain name for Event Hubs. Most likely, {yournamespace}.servicebus.windows.net</param>
        /// <param name="eventHubPath">The name of the EventHub.</param>
        /// <param name="consumerGroupName">The name of the consumer group within the Event Hub.</param>
        /// <param name="tokenProvider">Token provider which will generate security tokens for authorization.</param>
        /// <param name="checkpointManager">Object implementing ICheckpointManager which handles partition checkpointing.</param>
        /// <param name="leaseManager">Object implementing ILeaseManager which handles leases for partitions.</param>
        /// <param name="operationTimeout">Operation timeout for Event Hubs operations.</param>
        /// <param name="transportType">Transport type on connection.</param>
        public EventProcessorHost(
            string hostName,
            Uri endpointAddress,
            string eventHubPath,
            string consumerGroupName,
            ITokenProvider tokenProvider,
            ICheckpointManager checkpointManager,
            ILeaseManager leaseManager,
            TimeSpan?operationTimeout   = null,
            TransportType transportType = TransportType.Amqp)
        {
            Guard.ArgumentNotNullOrWhiteSpace(nameof(hostName), hostName);
            Guard.ArgumentNotNull(nameof(endpointAddress), endpointAddress);
            Guard.ArgumentNotNullOrWhiteSpace(nameof(eventHubPath), eventHubPath);
            Guard.ArgumentNotNullOrWhiteSpace(nameof(consumerGroupName), consumerGroupName);
            Guard.ArgumentNotNull(nameof(tokenProvider), tokenProvider);
            Guard.ArgumentNotNull(nameof(checkpointManager), checkpointManager);
            Guard.ArgumentNotNull(nameof(leaseManager), leaseManager);

            this.HostName          = hostName;
            this.EndpointAddress   = endpointAddress;
            this.EventHubPath      = eventHubPath;
            this.ConsumerGroupName = consumerGroupName;
            this.tokenProvider     = tokenProvider;
            this.CheckpointManager = checkpointManager;
            this.LeaseManager      = leaseManager;
            this.TransportType     = transportType;
            this.OperationTimeout  = operationTimeout ?? ClientConstants.DefaultOperationTimeout;
            this.PartitionManager  = new PartitionManager(this);
            ProcessorEventSource.Log.EventProcessorHostCreated(this.HostName, this.EventHubPath);
        }
Beispiel #4
0
        /// <summary>
        /// Builds a new instance of the <see cref="IChangeFeedProcessor"/> with the specified configuration.
        /// </summary>
        /// <returns>An instance of <see cref="IChangeFeedProcessor"/>.</returns>
        public async Task <IChangeFeedProcessor> BuildAsync()
        {
            if (this.hostName == null)
            {
                throw new InvalidOperationException("Host name was not specified");
            }

            if (this.feedCollectionLocation == null)
            {
                throw new InvalidOperationException(nameof(this.feedCollectionLocation) + " was not specified");
            }

            if (this.leaseCollectionLocation == null)
            {
                throw new InvalidOperationException(nameof(this.leaseCollectionLocation) + " was not specified");
            }

            if (this.observerFactory == null)
            {
                throw new InvalidOperationException("Observer was not specified");
            }

            await this.InitializeCollectionPropertiesForBuildAsync().ConfigureAwait(false);

            ILeaseManager leaseManager = await this.GetLeaseManagerAsync().ConfigureAwait(false);

            IPartitionManager partitionManager = await this.BuildPartitionManagerAsync(leaseManager).ConfigureAwait(false);

            return(new ChangeFeedProcessor(partitionManager));
        }
        public LeaderConfiguration(
            Func <T, CancellationToken, Task> startup,
            string nodeId,
            ILeaseManager leaseManager,
            LeaseConfiguration leaseConfiguration,
            CancellationTokenSource serviceIsStopping,
            Action <bool> whenLeaderIsElected,
            TimeSpan heartBeatInterval,
            Func <bool, CancellationToken, Task> onHeartBeat)
        {
            Startup      = startup ?? throw new ArgumentNullException(nameof(startup));
            LeaseManager = leaseManager ?? throw new ArgumentNullException(nameof(leaseManager));

            if (string.IsNullOrEmpty(nodeId))
            {
                throw new ArgumentException("Value cannot be null or empty.", nameof(nodeId));
            }

            NodeId                   = nodeId;
            LeaseConfiguration       = leaseConfiguration;
            ServiceIsStopping        = serviceIsStopping;
            this.whenLeaderIsElected = whenLeaderIsElected;
            HeartBeatInterval        = heartBeatInterval;
            OnHeartBeat              = onHeartBeat;
        }
Beispiel #6
0
        public LeaderConfiguration(
            Func <T, CancellationToken, Task> startup,
            string nodeId,
            ILeaseManager leaseManager,
            TimeSpan leaseUpdateEvery,
            TimeSpan leaderCheckEvery,
            CancellationTokenSource serviceIsStopping,
            Action <bool> whenLeaderIsElected)
        {
            Startup      = startup ?? throw new ArgumentNullException(nameof(startup));
            LeaseManager = leaseManager ?? throw new ArgumentNullException(nameof(leaseManager));

            if (leaseUpdateEvery <= TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(leaseUpdateEvery), "Must not be less than or equal to zero.");
            }

            if (leaderCheckEvery <= TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(leaseUpdateEvery), "Must not be less than or equal to zero.");
            }

            if (string.IsNullOrEmpty(nodeId))
            {
                throw new ArgumentException("Value cannot be null or empty.", nameof(nodeId));
            }

            NodeId              = nodeId;
            LeaseUpdateEvery    = leaseUpdateEvery;
            LeaderCheckEvery    = leaderCheckEvery;
            ServiceIsStopping   = serviceIsStopping;
            WhenLeaderIsElected = whenLeaderIsElected;
        }
        public PartitionControllerTests()
        {
            lease = Mock.Of <ILease>();
            Mock.Get(lease)
            .Setup(l => l.PartitionId)
            .Returns("partitionId");

            partitionProcessor         = MockPartitionProcessor();
            leaseRenewer               = MockRenewer();
            observer                   = MockObserver();
            partitionSupervisorFactory = Mock.Of <IPartitionSupervisorFactory>(f => f.Create(lease) == new PartitionSupervisor(lease, observer, partitionProcessor, leaseRenewer));

            leaseManager = Mock.Of <ILeaseManager>();
            Mock.Get(leaseManager).Reset(); // Reset implicit/by default setup of properties.
            Mock.Get(leaseManager)
            .Setup(manager => manager.AcquireAsync(lease))
            .ReturnsAsync(lease);
            Mock.Get(leaseManager)
            .Setup(manager => manager.ReleaseAsync(lease))
            .Returns(Task.CompletedTask);
            var leaseContainer = Mock.Of <ILeaseContainer>();

            synchronizer = Mock.Of <IPartitionSynchronizer>();
            sut          = new PartitionController(leaseContainer, leaseManager, partitionSupervisorFactory, synchronizer);
        }
Beispiel #8
0
        public async Task SplitPartitionAsync_ShouldReturnOnlyNewLeases_IfSplitWasAlreadyPerformed()
        {
            const string lastKnowToken = "last know token";

            IEnumerable <PartitionKeyRange> keyRanges = new[]
            {
                new PartitionKeyRange
                {
                    Id = "20", Parents = new Collection <string>(new[] { "10" })
                },
                new PartitionKeyRange
                {
                    Id = "30", Parents = new Collection <string>(new[] { "10" })
                }
            };

            var lease = Mock.Of <ILease>(l => l.PartitionId == "10" && l.ContinuationToken == lastKnowToken);

            var keyRangeResponse = Mock.Of <IFeedResponse <PartitionKeyRange> >(r => r.GetEnumerator() == keyRanges.GetEnumerator());
            IChangeFeedDocumentClient documentClient = Mock.Of <IChangeFeedDocumentClient>(c => c.ReadPartitionKeyRangeFeedAsync(It.IsAny <string>(), It.IsAny <FeedOptions>()) == Task.FromResult(keyRangeResponse));

            var           lease20      = Mock.Of <ILease>();
            ILeaseManager leaseManager = Mock.Of <ILeaseManager>(m =>
                                                                 m.CreateLeaseIfNotExistAsync("20", lastKnowToken) == Task.FromResult(lease20) &&
                                                                 m.CreateLeaseIfNotExistAsync("30", lastKnowToken) == Task.FromResult <ILease>(null));

            var sut = new PartitionSynchronizer(documentClient, "collectionlink", leaseManager, 1, int.MaxValue);
            IEnumerable <ILease> result = await sut.SplitPartitionAsync(lease);

            Assert.NotNull(result);
            Assert.Equal(new[] { lease20 }, result);
        }
Beispiel #9
0
        public LeaseCleanup(ILeaseManager manager)
        {
            _manager      = manager;
            _cancellation = new CancellationTokenSource();

            Task.Run(() => Work(_cancellation.Token));
        }
Beispiel #10
0
        public LeaseCollectionBalancer(
            string leaseType,
            AzureStorageOrchestrationServiceSettings settings,
            string accountName,
            ILeaseManager <T> leaseManager,
            LeaseCollectionBalancerOptions options,
            Func <string, bool> shouldAquireLeaseDelegate = null,
            Func <string, bool> shouldRenewLeaseDelegate  = null)

        {
            this.leaseType    = leaseType;
            this.accountName  = accountName;
            this.taskHub      = settings.TaskHubName;
            this.workerName   = settings.WorkerId;
            this.leaseManager = leaseManager;
            this.options      = options;
            this.settings     = settings;

            this.shouldAquireLeaseDelegate = shouldAquireLeaseDelegate ?? DefaultLeaseDecisionDelegate;
            this.shouldRenewLeaseDelegate  = shouldRenewLeaseDelegate ?? DefaultLeaseDecisionDelegate;

            this.currentlyOwnedShards    = new ConcurrentDictionary <string, T>();
            this.keepRenewingDuringClose = new ConcurrentDictionary <string, T>();
            this.leaseObserverManager    = new LeaseObserverManager(this);
        }
        async Task InitializeAsync()
        {
            this.documentClient = new DocumentClient(this.collectionLocation.Uri, this.collectionLocation.MasterKey, this.collectionLocation.ConnectionPolicy);

            Uri      databaseUri = UriFactory.CreateDatabaseUri(this.collectionLocation.DatabaseName);
            Database database    = await this.documentClient.ReadDatabaseAsync(databaseUri);

            Uri collectionUri = UriFactory.CreateDocumentCollectionUri(this.collectionLocation.DatabaseName, this.collectionLocation.CollectionName);
            ResourceResponse <DocumentCollection> collectionResponse = await this.documentClient.ReadDocumentCollectionAsync(
                collectionUri,
                new RequestOptions { PopulateQuotaInfo = true });

            DocumentCollection collection = collectionResponse.Resource;

            this.collectionSelfLink = collection.SelfLink;

            // Grab the options-supplied prefix if present otherwise leave it empty.
            string optionsPrefix = this.options.LeasePrefix ?? string.Empty;

            // Beyond this point all access to collection is done via this self link: if collection is removed, we won't access new one using same name by accident.
            this.leasePrefix = string.Format(CultureInfo.InvariantCulture, "{0}{1}_{2}_{3}", optionsPrefix, this.collectionLocation.Uri.Host, database.ResourceId, collection.ResourceId);

            var leaseManager = new DocumentServiceLeaseManager(
                this.auxCollectionLocation,
                this.leasePrefix,
                this.options.LeaseExpirationInterval,
                this.options.LeaseRenewInterval);
            await leaseManager.InitializeAsync();

            this.leaseManager      = leaseManager;
            this.checkpointManager = (ICheckpointManager)leaseManager;

            if (this.options.DiscardExistingLeases)
            {
                TraceLog.Warning(string.Format("Host '{0}': removing all leases, as requested by ChangeFeedHostOptions", this.HostName));
                await this.leaseManager.DeleteAllAsync();
            }

            // Note: lease store is never stale as we use monitored colleciton Rid as id prefix for aux collection.
            // Collection was removed and re-created, the rid would change.
            // If it's not deleted, it's not stale. If it's deleted, it's not stale as it doesn't exist.
            await this.leaseManager.CreateLeaseStoreIfNotExistsAsync();

            var ranges = new Dictionary <string, PartitionKeyRange>();

            foreach (var range in await this.EnumPartitionKeyRangesAsync(this.collectionSelfLink))
            {
                ranges.Add(range.Id, range);
            }

            TraceLog.Informational(string.Format("Source collection: '{0}', {1} partition(s), {2} document(s)", this.collectionLocation.CollectionName, ranges.Count, GetDocumentCount(collectionResponse)));

            await this.CreateLeases(ranges);

            this.partitionManager = new PartitionManager <DocumentServiceLease>(this.HostName, this.leaseManager, this.options);
            await this.partitionManager.SubscribeAsync(this);

            await this.partitionManager.InitializeAsync();
        }
Beispiel #12
0
 public PartitionSynchronizer(IChangeFeedDocumentClient documentClient, string collectionSelfLink, ILeaseManager leaseManager, int degreeOfParallelism, int maxBatchSize)
 {
     this.documentClient      = documentClient;
     this.collectionSelfLink  = collectionSelfLink;
     this.leaseManager        = leaseManager;
     this.degreeOfParallelism = degreeOfParallelism;
     this.maxBatchSize        = maxBatchSize;
 }
Beispiel #13
0
 /// <summary>
 /// Sets the <see cref="ILeaseManager"/> to be used to manage leases.
 /// </summary>
 /// <param name="leaseManager">The instance of <see cref="ILeaseManager"/> to use.</param>
 /// <returns>The instance of <see cref="ChangeFeedProcessorBuilder"/> to use.</returns>
 public ChangeFeedProcessorBuilder WithLeaseManager(ILeaseManager leaseManager)
 {
     if (leaseManager == null)
     {
         throw new ArgumentNullException(nameof(leaseManager));
     }
     this.leaseManager = leaseManager;
     return(this);
 }
 public LeaderConfigurationBuilder()
 {
     timeBetweenLeaseUpdates         = DefaultTimeBetweenLeaseUpdates;
     timeBetweenCheckingLeaderHealth = DefaultTimeBetweenCheckingLeaderHealth;
     nodeId              = Guid.NewGuid().ToString();
     leaseManager        = new InMemoryLeaseManager(nodeId);
     whenLeaderIsElected = b => { };
     serviceIsStopping   = new CancellationTokenSource();
 }
        public LeaseConfigurationBuilder WithLeaseManager(ILeaseManager manager)
        {
            if (manager == null)
            {
                throw new ArgumentNullException(nameof(manager));
            }

            managerFunc = c => manager;
            return(this);
        }
        public PartitionManager(string workerName, ILeaseManager <T> leaseManager, ChangeFeedHostOptions options)
        {
            this.workerName   = workerName;
            this.leaseManager = leaseManager;
            this.options      = options;

            this.currentlyOwnedPartitions = new ConcurrentDictionary <string, T>();
            this.keepRenewingDuringClose  = new ConcurrentDictionary <string, T>();
            this.partitionObserverManager = new PartitionObserverManager(this);
        }
Beispiel #17
0
 public PartitionController(
     ILeaseContainer leaseContainer,
     ILeaseManager leaseManager,
     IPartitionSupervisorFactory partitionSupervisorFactory,
     IPartitionSynchronizer synchronizer)
 {
     this.leaseContainer             = leaseContainer;
     this.leaseManager               = leaseManager;
     this.partitionSupervisorFactory = partitionSupervisorFactory;
     this.synchronizer               = synchronizer;
 }
 /// <summary>
 /// Create host wrapper
 /// </summary>
 /// <param name="factory"></param>
 /// <param name="config"></param>
 /// <param name="logger"></param>
 /// <param name="checkpoint"></param>
 /// <param name="lease"></param>
 public EventProcessorHost(IEventProcessorFactory factory,
                           IEventProcessorConfig config, ICheckpointManager checkpoint,
                           ILeaseManager lease, ILogger logger)
 {
     _logger     = logger ?? throw new ArgumentNullException(nameof(logger));
     _config     = config ?? throw new ArgumentNullException(nameof(config));
     _factory    = factory ?? throw new ArgumentNullException(nameof(factory));
     _lease      = lease;
     _checkpoint = checkpoint;
     _lock       = new SemaphoreSlim(1);
 }
Beispiel #19
0
        public DhcpServer(ILogger logger, ILeaseManager leaseManager, IDhcpConfiguration configuration,
                          IDhcpMessageSerializer messageSerializer, IDhcpPacketSerializer packetSeralizer)
        {
            Log               = logger;
            Configuration     = configuration;
            LeaseManager      = leaseManager;
            MessageSerializer = messageSerializer;
            PacketSerializer  = packetSeralizer;

            _requestLock = new SemaphoreSlim(1);
        }
        public PartitionManager(string accountName, string taskHub, string workerName, ILeaseManager <T> leaseManager, PartitionManagerOptions options)
        {
            this.accountName  = accountName;
            this.taskHub      = taskHub;
            this.workerName   = workerName;
            this.leaseManager = leaseManager;
            this.options      = options;

            this.currentlyOwnedShards     = new ConcurrentDictionary <string, T>();
            this.keepRenewingDuringClose  = new ConcurrentDictionary <string, T>();
            this.partitionObserverManager = new PartitionObserverManager(this);
        }
Beispiel #21
0
        /// <summary>
        /// Create a new host to process events from an Event Hub.
        ///
        /// <para>This overload of the constructor allows maximum flexibility.
        /// This one allows the caller to specify the name of the processor host as well.
        /// The overload also allows the caller to provide their own lease and checkpoint managers to replace the built-in
        /// ones based on Azure Storage.</para>
        /// </summary>
        /// <param name="hostName">Name of the processor host. MUST BE UNIQUE. Strongly recommend including a Guid to ensure uniqueness.</param>
        /// <param name="eventHubPath">The name of the EventHub.</param>
        /// <param name="consumerGroupName">The name of the consumer group within the Event Hub.</param>
        /// <param name="eventHubConnectionString">Connection string for the Event Hub to receive from.</param>
        /// <param name="checkpointManager">Object implementing ICheckpointManager which handles partition checkpointing.</param>
        /// <param name="leaseManager">Object implementing ILeaseManager which handles leases for partitions.</param>
        public EventProcessorHost(
            string hostName,
            string eventHubPath,
            string consumerGroupName,
            string eventHubConnectionString,
            ICheckpointManager checkpointManager,
            ILeaseManager leaseManager)
        {
            if (string.IsNullOrEmpty(consumerGroupName))
            {
                throw new ArgumentNullException(nameof(consumerGroupName));
            }
            else if (checkpointManager == null || leaseManager == null)
            {
                throw new ArgumentNullException(checkpointManager == null ? nameof(checkpointManager) : nameof(leaseManager));
            }

            var csb = new EventHubsConnectionStringBuilder(eventHubConnectionString);

            if (string.IsNullOrEmpty(eventHubPath))
            {
                // Entity path is expected in the connection string if not provided with eventHubPath parameter.
                if (string.IsNullOrEmpty(csb.EntityPath))
                {
                    throw new ArgumentException(nameof(eventHubConnectionString),
                                                "Provide EventHub entity path either in eventHubPath parameter or in eventHubConnectionString.");
                }
            }
            else
            {
                // Entity path should not conflict with connection string.
                if (!string.IsNullOrEmpty(csb.EntityPath) &&
                    string.Compare(csb.EntityPath, eventHubPath, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    throw new ArgumentException(nameof(eventHubConnectionString),
                                                "Provided EventHub path in eventHubPath parameter conflicts with the path in provided EventHubs connection string.");
                }

                csb.EntityPath = eventHubPath;
            }

            this.HostName                 = hostName;
            this.EventHubPath             = csb.EntityPath;
            this.ConsumerGroupName        = consumerGroupName;
            this.eventHubConnectionString = csb.ToString();
            this.CheckpointManager        = checkpointManager;
            this.LeaseManager             = leaseManager;
            this.TransportType            = csb.TransportType;
            this.OperationTimeout         = csb.OperationTimeout;
            this.EndpointAddress          = csb.Endpoint;
            this.PartitionManager         = new PartitionManager(this);
            ProcessorEventSource.Log.EventProcessorHostCreated(this.HostName, this.EventHubPath);
        }
        public RemainingWorkEstimatorTests()
        {
            var document = new Document();

            document.SetPropertyValue("_lsn", "10");
            documents = new List <Document> {
                document
            };

            feedResponse = Mock.Of <IFeedResponse <Document> >();
            Mock.Get(feedResponse)
            .Setup(response => response.SessionToken)
            .Returns("0:15");

            Mock.Get(feedResponse)
            .Setup(response => response.Count)
            .Returns(documents.Count);

            Mock.Get(feedResponse)
            .Setup(response => response.GetEnumerator())
            .Returns(documents.GetEnumerator());

            lease = Mock.Of <ILease>();
            Mock.Get(lease)
            .Setup(l => l.PartitionId)
            .Returns("partitionId");

            leaseManager = Mock.Of <ILeaseManager>();
            Mock.Get(leaseManager)
            .Setup(manager => manager.ListAllLeasesAsync())
            .ReturnsAsync(new List <ILease>()
            {
                lease
            });

            documentQuery = Mock.Of <IChangeFeedDocumentQuery <Document> >();
            Mock.Get(documentQuery)
            .Setup(query => query.HasMoreResults)
            .Returns(false);

            Mock.Get(documentQuery)
            .Setup(query => query.ExecuteNextAsync <Document>(It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => feedResponse)
            .Callback(() => cancellationTokenSource.Cancel());

            docClient = Mock.Of <IChangeFeedDocumentClient>();
            Mock.Get(docClient)
            .Setup(ex => ex.CreateDocumentChangeFeedQuery(collectionSelfLink, It.IsAny <ChangeFeedOptions>()))
            .Returns(documentQuery);

            remainingWorkEstimator = new RemainingWorkEstimator(leaseManager, docClient, collectionSelfLink);
        }
Beispiel #23
0
        async Task InitializeAsync()
        {
            this.documentClient = new DocumentClient(this.collectionLocation.Uri, this.collectionLocation.MasterKey, this.collectionLocation.ConnectionPolicy);

            Uri      databaseUri = UriFactory.CreateDatabaseUri(this.collectionLocation.DatabaseName);
            Database database    = await this.documentClient.ReadDatabaseAsync(databaseUri);

            Uri collectionUri             = UriFactory.CreateDocumentCollectionUri(this.collectionLocation.DatabaseName, this.collectionLocation.CollectionName);
            DocumentCollection collection = await this.documentClient.ReadDocumentCollectionAsync(collectionUri);

            this.collectionSelfLink = collection.SelfLink;

            // Beyond this point all access to colleciton is done via this self link: if collection is removed, we won't access new one using same name by accident.
            this.leasePrefix = string.Format(CultureInfo.InvariantCulture, "{0}_{1}_{2}", this.collectionLocation.Uri.Host, database.ResourceId, collection.ResourceId);

            var leaseManager = new DocumentServiceLeaseManager(
                this.auxCollectionLocation,
                this.leasePrefix,
                this.options.LeaseExpirationInterval,
                this.options.LeaseRenewInterval);
            await leaseManager.InitializeAsync();

            this.leaseManager      = leaseManager;
            this.checkpointManager = (ICheckpointManager)leaseManager;

            if (this.options.DiscardExistingLeases)
            {
                TraceLog.Warning(string.Format("Host '{0}': removing all leases, as requested by ChangeFeedHostOptions", this.HostName));
                await this.leaseManager.DeleteAllAsync();
            }

            // Note: lease store is never stale as we use monitored colleciton Rid as id prefix for aux collection.
            // Collection was removed and re-created, the rid would change.
            // If it's not deleted, it's not stale. If it's deleted, it's not stale as it doesn't exist.
            await this.leaseManager.CreateLeaseStoreIfNotExistsAsync();

            string[] rangeIds = await this.EnumPartitionKeyRangeIds(this.collectionSelfLink);

            Parallel.ForEach(rangeIds, async rangeId => {
                this.statsSinceLastCheckpoint.AddOrUpdate(
                    rangeId,
                    new CheckpointStats(),
                    (partitionId, existingStats) => existingStats);

                await this.leaseManager.CreateLeaseIfNotExistAsync(rangeId);
            });

            this.partitionManager = new PartitionManager <DocumentServiceLease>(this.HostName, this.leaseManager, this.options);
            await this.partitionManager.SubscribeAsync(this);

            await this.partitionManager.InitializeAsync();
        }
Beispiel #24
0
        private static void BuildSubject(string nodeid, ILeaseManager manager, Action <bool> whenLeaderElected, out TestService servicewithStopSupport, out Runner <TestService> runner)
        {
            var config = new LeaderConfigurationBuilder <TestService>()
                         .SetNodeId(nodeid)
                         .AttemptToBeTheLeaderEvery(TimeSpan.FromMilliseconds(100))
                         .UpdateLeaseEvery(TimeSpan.FromMilliseconds(50))
                         .WhenStarted(async(s, token) => await s.Start(token))
                         .WhenLeaderIsElected(whenLeaderElected)
                         .WithLeaseManager(manager);

            servicewithStopSupport = new TestService();
            runner = new Runner <TestService>(servicewithStopSupport, config.Build());
        }
Beispiel #25
0
        public PartitionManager(AzureStorageOrchestrationServiceSettings settings, string accountName, string workerName, ILeaseManager <T> leaseManager, PartitionManagerOptions options)
        {
            this.accountName  = accountName;
            this.taskHub      = settings.TaskHubName;
            this.workerName   = workerName;
            this.leaseManager = leaseManager;
            this.options      = options;
            this.settings     = settings;

            this.currentlyOwnedShards     = new ConcurrentDictionary <string, T>();
            this.keepRenewingDuringClose  = new ConcurrentDictionary <string, T>();
            this.partitionObserverManager = new PartitionObserverManager(this);
        }
Beispiel #26
0
        async Task InitializeStoresAsync() //throws InterruptedException, ExecutionException, ExceptionWithAction
        {
            // Make sure the lease store exists
            ILeaseManager leaseManager = this.host.LeaseManager;

            if (!await leaseManager.LeaseStoreExistsAsync().ConfigureAwait(false))
            {
                await RetryAsync(() => leaseManager.CreateLeaseStoreIfNotExistsAsync(), null, "Failure creating lease store for this Event Hub, retrying",
                                 "Out of retries creating lease store for this Event Hub", EventProcessorHostActionStrings.CreatingLeaseStore, 5).ConfigureAwait(false);
            }
            // else
            //	lease store already exists, no work needed

            var partitionIds = await this.GetPartitionIdsAsync().ConfigureAwait(false);

            // Now make sure the leases exist
            var createLeaseTasks = new List <Task>();

            foreach (string id in partitionIds)
            {
                var subjectId = id;
                createLeaseTasks.Add(RetryAsync(() => leaseManager.CreateLeaseIfNotExistsAsync(subjectId), subjectId, $"Failure creating lease for partition {subjectId}, retrying",
                                                $"Out of retries creating lease for partition {subjectId}", EventProcessorHostActionStrings.CreatingLease, 5));
            }

            await Task.WhenAll(createLeaseTasks).ConfigureAwait(false);

            // Make sure the checkpoint store exists
            ICheckpointManager checkpointManager = this.host.CheckpointManager;

            if (!await checkpointManager.CheckpointStoreExistsAsync().ConfigureAwait(false))
            {
                await RetryAsync(() => checkpointManager.CreateCheckpointStoreIfNotExistsAsync(), null, "Failure creating checkpoint store for this Event Hub, retrying",
                                 "Out of retries creating checkpoint store for this Event Hub", EventProcessorHostActionStrings.CreatingCheckpointStore, 5).ConfigureAwait(false);
            }
            // else
            //	checkpoint store already exists, no work needed

            // Now make sure the checkpoints exist
            var createCheckpointTasks = new List <Task>();

            foreach (string id in partitionIds)
            {
                var subjectId = id;
                createCheckpointTasks.Add(RetryAsync(() => checkpointManager.CreateCheckpointIfNotExistsAsync(subjectId), subjectId, $"Failure creating checkpoint for partition {subjectId}, retrying",
                                                     $"Out of retries creating checkpoint for partition {subjectId}", EventProcessorHostActionStrings.CreatingCheckpoint, 5));
            }

            await Task.WhenAll(createCheckpointTasks).ConfigureAwait(false);
        }
        public async Task <bool> RetryAsync <T>(ILeaseManager <T> leaseManager, T key, TimeSpan leaseDuration, int maxRetries,
                                                bool createLazyLeaseObject, Func <Task> func)
        {
            TimeSpan retryDelay = TimeSpan.FromSeconds(leaseDuration.TotalSeconds / maxRetries);
            string   leaseId    = null;
            int      retry      = 0;

            while (String.IsNullOrWhiteSpace(leaseId) && retry < maxRetries)
            {
                _logger?.LogTrace("LeasedRetry - RetryAsync - attempting to acquire lease {KEY}, retry {RETRY}", key, retry);
                try
                {
                    leaseId = await leaseManager.LeaseAsync(key, leaseDuration);
                }
                catch (Exception)
                {
                    leaseId = null;
                }

                if (String.IsNullOrWhiteSpace(leaseId))
                {
                    if (retry == 0)
                    {
                        await leaseManager.CreateLeaseObjectIfNotExistAsync(key);
                    }
                    retry++;
                    await Task.Delay(retryDelay);
                }
            }

            if (String.IsNullOrWhiteSpace(leaseId))
            {
                _logger?.LogTrace("LeasedRetry - RetryAsync - failed to acquire lease {KEY} after retry {RETRYCOUNT} and giving up", key, retry);
                return(false);
            }

            _logger?.LogTrace("LeasedRetry - RetryAsync - acquired lease {KEY} after retry {RETRYCOUNT}", key, retry);

            try
            {
                await func();
            }
            finally
            {
                leaseManager.ReleaseAsync(key, leaseId).Wait();
                _logger?.LogTrace("LeasedRetry - RetryAsync - released lease {KEY}", key);
            }

            return(true);
        }
        private void ConfigureInstance(ILogger logger, IMetricFactory metricFactory, FixedProcessorClientOptions options, ILeaseManager leaseManager, ICheckpointManager checkpointManager)
        {
            Guard.NotNull(nameof(logger), logger);
            Guard.NotNull(nameof(leaseManager), leaseManager);
            Guard.NotNull(nameof(checkpointManager), checkpointManager);
            Guard.NotNull(nameof(options), options);
            Guard.NotNull(nameof(metricFactory), metricFactory);

            _leaseManager      = leaseManager;
            _checkpointManager = checkpointManager;
            _options           = options;
            _logger            = logger;
            _metricFactory     = metricFactory;

            _errorCounter                  = _metricFactory.CreateCounter("fpc-processing-error-count", "The number of processing errors raised since the start of the processor.", false, new string[0]);
            _partitionStopProcessing       = _metricFactory.CreateCounter("fpc-partition-stop-count", "The number of processing stop events raised since the start of the processor.", false, new string[0]);
            _partitionInitializeProcessing = _metricFactory.CreateCounter("fpc-partition-init-count", "The number of processing initialization events raised since the start of the processor.", false, new string[0]);
        }
Beispiel #29
0
        /// <summary>
        /// Builds a new instance of the <see cref="IRemainingWorkEstimator"/> to estimate pending work with the specified configuration.
        /// </summary>
        /// <returns>An instance of <see cref="IRemainingWorkEstimator"/>.</returns>
        public async Task <IRemainingWorkEstimator> BuildEstimatorAsync()
        {
            if (this.feedCollectionLocation == null)
            {
                throw new InvalidOperationException(nameof(this.feedCollectionLocation) + " was not specified");
            }

            if (this.leaseCollectionLocation == null)
            {
                throw new InvalidOperationException(nameof(this.leaseCollectionLocation) + " was not specified");
            }

            await this.InitializeCollectionPropertiesForBuildAsync().ConfigureAwait(false);

            ILeaseManager leaseManager = await this.GetLeaseManagerAsync().ConfigureAwait(false);

            IRemainingWorkEstimator remainingWorkEstimator = new RemainingWorkEstimator(leaseManager, this.feedDocumentClient, this.feedCollectionLocation.GetCollectionSelfLink());

            return(remainingWorkEstimator);
        }
Beispiel #30
0
        private async Task <ILeaseManager> GetLeaseManagerAsync()
        {
            if (this.leaseManager == null)
            {
                string leasePrefix         = this.GetLeasePrefix();
                var    leaseManagerBuilder = new LeaseManagerBuilder()
                                             .WithLeasePrefix(leasePrefix)
                                             .WithLeaseCollection(this.leaseCollectionLocation)
                                             .WithHostName(this.hostName);

                if (this.leaseDocumentClient != null)
                {
                    leaseManagerBuilder = leaseManagerBuilder.WithLeaseDocumentClient(this.leaseDocumentClient);
                }

                this.leaseManager = await leaseManagerBuilder.BuildAsync().ConfigureAwait(false);
            }

            return(this.leaseManager);
        }