Example #1
0
        private async Task <RebalancingResult> AssignResourcesPhaseAsync(CancellationToken rebalancingToken,
                                                                         ResourcesZnode resources,
                                                                         ClientsZnode clients)
        {
            logger.Info(clientId, "Coordinator - Assign resources to clients");
            Queue <string>            resourcesToAssign   = new(resources.Resources);
            List <ResourceAssignment> resourceAssignments = new();
            int clientIndex = 0;

            while (resourcesToAssign.Any())
            {
                resourceAssignments.Add(new ResourceAssignment
                {
                    ClientId = GetClientId(clients.ClientPaths[clientIndex]), Resource = resourcesToAssign.Dequeue()
                });

                clientIndex++;
                if (clientIndex >= clients.ClientPaths.Count)
                {
                    clientIndex = 0;
                }
            }

            // write assignments back to resources znode
            resources.ResourceAssignments.Assignments = resourceAssignments;
            resourcesVersion = await zooKeeperService.SetResourcesAsync(resources);

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            status.RebalancingStatus = RebalancingStatus.ResourcesGranted;
            status.Version           = await zooKeeperService.SetStatus(status);

            if (onStartDelay.Ticks > 0)
            {
                logger.Info(clientId, $"Coordinator - Delaying on start for {(int)onStartDelay.TotalMilliseconds}ms");
                await WaitFor(onStartDelay, rebalancingToken);
            }

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            List <string> leaderAssignments =
                resourceAssignments.Where(x => x.ClientId == clientId).Select(x => x.Resource).ToList();
            await store.InvokeOnStartActionsAsync(clientId, "Coordinator", leaderAssignments, rebalancingToken,
                                                  coordinatorToken);

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            return(RebalancingResult.Complete);
        }
Example #2
0
        private async Task <RebalancingResult> RebalanceAsync(CancellationToken rebalancingToken)
        {
            Stopwatch sw = new();

            sw.Start();

            logger.Info(clientId, "Coordinator - Get clients and resources list");
            ClientsZnode clients = await zooKeeperService.GetActiveClientsAsync();

            ResourcesZnode resources = await zooKeeperService.GetResourcesAsync(null, null);

            if (resources.Version != resourcesVersion)
            {
                throw new ZkStaleVersionException(
                          "Resources znode version does not match expected value, indicates another client has been made coordinator and is executing a rebalancing.");
            }

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            // if no resources were changed and there are more clients than resources then check
            // to see if rebalancing is necessary. If existing assignments are still valid then
            // a new client or the loss of a client with no assignments need not trigger a rebalancing
            if (!IsRebalancingRequired(clients, resources))
            {
                logger.Info(clientId,
                            "Coordinator - No rebalancing required. No resource change. No change to existing clients. More clients than resources.");
                return(RebalancingResult.Complete);
            }

            logger.Info(clientId,
                        $"Coordinator - Assign resources ({string.Join(",", resources.Resources)}) to clients ({string.Join(",", clients.ClientPaths.Select(GetClientId))})");
            Queue <string>            resourcesToAssign   = new(resources.Resources);
            List <ResourceAssignment> resourceAssignments = new();
            int clientIndex = 0;

            while (resourcesToAssign.Any())
            {
                resourceAssignments.Add(new ResourceAssignment
                {
                    ClientId = GetClientId(clients.ClientPaths[clientIndex]), Resource = resourcesToAssign.Dequeue()
                });

                clientIndex++;
                if (clientIndex >= clients.ClientPaths.Count)
                {
                    clientIndex = 0;
                }
            }

            // write assignments back to resources znode
            resources.ResourceAssignments.Assignments = resourceAssignments;
            resourcesVersion = await zooKeeperService.SetResourcesAsync(resources);

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            await store.InvokeOnStopActionsAsync(clientId, "Coordinator");

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            if (onStartDelay.Ticks > 0)
            {
                logger.Info(clientId, $"Coordinator - Delaying on start for {(int)onStartDelay.TotalMilliseconds}ms");
                await WaitFor(onStartDelay, rebalancingToken);
            }

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            List <string> leaderAssignments = resourceAssignments
                                              .Where(x => x.ClientId == clientId)
                                              .Select(x => x.Resource)
                                              .ToList();
            await store.InvokeOnStartActionsAsync(clientId, "Coordinator", leaderAssignments, rebalancingToken,
                                                  coordinatorToken);

            if (rebalancingToken.IsCancellationRequested)
            {
                return(RebalancingResult.Cancelled);
            }

            return(RebalancingResult.Complete);
        }