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; }
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)); }
/// <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); }
/// <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; }
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); }
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); }
public LeaseCleanup(ILeaseManager manager) { _manager = manager; _cancellation = new CancellationTokenSource(); Task.Run(() => Work(_cancellation.Token)); }
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(); }
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; }
/// <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); }
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); }
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); }
/// <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); }
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(); }
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()); }
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); }
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]); }
/// <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); }
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); }