Beispiel #1
0
        public async ValueTask <bool> RemoveSubscription()
        {
            if (_disposed == 1)
            {
                throw new ObjectDisposedException(nameof(EventSubscriptionBase));
            }

            // accepted race condition, _busy can be disposed here and will throw an ObjectDisposedException

            await _busy.WaitAsync().CfAwait();

            try
            {
                if (_subscriptionsCount == 0)
                {
                    return(true);                          // TODO: should we throw?
                }
                if (_subscriptionsCount > 1)
                {
                    return(true);
                }

                var removed = await ClusterEvents.RemoveSubscriptionAsync(_subscriptionId).CfAwait();

                if (removed)
                {
                    _subscriptionsCount--;
                }
                return(removed);
            }
            finally
            {
                _busy.Release();
            }
        }
Beispiel #2
0
        public async ValueTask DisposeAsync()
        {
            if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 1)
            {
                return;
            }

            await _busy.WaitAsync().CfAwait();

            try
            {
                if (_subscriptionsCount == 0)
                {
                    return;
                }

                // remove, ignore result
                await ClusterEvents.RemoveSubscriptionAsync(_subscriptionId).CfAwait();
            }
            finally
            {
                _busy.Release();
            }

            _busy.Dispose();

            // this should not be a warning
            // https://github.com/dotnet/roslyn-analyzers/issues/3909
            // https://github.com/dotnet/roslyn-analyzers/issues/3675
            // https://github.com/dotnet/roslyn-analyzers/pull/3679
#pragma warning disable CA1816 // Dispose methods should call SuppressFinalize
            GC.SuppressFinalize(this);
#pragma warning restore CA1816
        }
Beispiel #3
0
        public async Task AddSubscription()
        {
            if (_disposed == 1)
            {
                throw new ObjectDisposedException(nameof(EventSubscriptionBase));
            }

            // accepted race condition, _busy can be disposed here and will throw an ObjectDisposedException

            await _busy.WaitAsync().CfAwait();

            try
            {
                _subscriptionsCount++;
                if (_subscriptionsCount > 1)
                {
                    return;
                }

                var subscription = CreateSubscription();
                await ClusterEvents.InstallSubscriptionAsync(subscription).CfAwait();

                _subscriptionId = subscription.Id;
            }
            finally
            {
                _busy.Release();
            }
        }
Beispiel #4
0
        public ClusterConnections(ClusterState clusterState, ClusterClusterEvents clusterClusterEvents, ClusterEvents clusterEvents, ClusterMembers clusterMembers, ISerializationService serializationService, Func <ValueTask> terminateAsync)
        {
            _clusterState         = clusterState;
            _clusterClusterEvents = clusterClusterEvents;
            _clusterEvents        = clusterEvents;
            _clusterMembers       = clusterMembers;
            _serializationService = serializationService;
            _terminateAsync       = terminateAsync;

            _logger = _clusterState.LoggerFactory.CreateLogger <ClusterConnections>();

            _authenticator = _clusterState.Options.Authentication.Authenticator.Service ??
                             new Authenticator(_clusterState.Options.Authentication);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ClusterClusterEvents"/> class.
        /// </summary>
        /// <param name="clusterState">The cluster state.</param>
        /// <param name="clusterMembers">The cluster members.</param>
        /// <param name="clusterEvents">The cluster events.</param>
        public ClusterClusterEvents(ClusterState clusterState, ClusterMembers clusterMembers, ClusterEvents clusterEvents)
        {
            _clusterState  = clusterState;
            _clusterEvents = clusterEvents;

            _objectLifecycleEventSubscription = new ObjectLifecycleEventSubscription(_clusterState, clusterEvents)
            {
                Handle = (eventType, args) => _onObjectLifeCycleEvent(eventType, args)
            };

            _partitionLostEventSubscription = new PartitionLostEventSubscription(_clusterState, clusterEvents, clusterMembers)
            {
                Handle = args => _onPartitionLost(args)
            };
        }
        /// <inheritdoc />
        public async ValueTask DisposeAsync()
        {
            if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 1)
            {
                return;
            }

            // disposing the cluster terminates all operations

            // change the state - the final NotConnected state will
            // be set by Connections when the last one goes down, and
            // the cluster is not active anymore
            State.NotifyState(ClientState.ShuttingDown);

            // we don't need heartbeat anymore
            await _heartbeat.DisposeAsync().CfAwait();

            // ClusterMessaging has nothing to dispose

            // ClusterEvents need to shutdown
            // - the events scheduler (always running)
            // - the task that ensures FIXME DOCUMENT
            // - the task that deals with ghost subscriptions (if it's running)
            await Events.DisposeAsync().CfAwait();

            // ClusterClusterEvents need to shutdown
            // - the two ObjectLifeCycle and PartitionLost subscriptions
            await ClusterEvents.DisposeAsync().CfAwait();

            // now it's time to dispose the connections, ie close all of them
            // and shutdown
            // - the reconnect task (if it's running)
            // - the task that connects members (always running)
            await Connections.DisposeAsync().CfAwait();

            // at that point we can get rid of members
            await Members.DisposeAsync().CfAwait();

            // and finally, of the state itself
            // which will shutdown
            // - the state changed queue (always running)
            await State.DisposeAsync().CfAwait();
        }
        private volatile int _disposed; // disposed flag

        /// <summary>
        /// Initializes a new instance of the <see cref="Cluster"/> class.
        /// </summary>
        /// <param name="options">The cluster configuration.</param>
        /// <param name="serializationService">The serialization service.</param>
        /// <param name="loggerFactory">A logger factory.</param>
        public Cluster(IClusterOptions options, SerializationService serializationService, ILoggerFactory loggerFactory)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (serializationService == null)
            {
                throw new ArgumentNullException(nameof(serializationService));
            }
            if (loggerFactory is null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            var clientName = string.IsNullOrWhiteSpace(options.ClientName)
                ? options.ClientNamePrefix + ClusterIdSequence.GetNext()
                : options.ClientName;

            var clusterName = string.IsNullOrWhiteSpace(options.ClusterName) ? "dev" : options.ClusterName;

            State = new ClusterState(options, clusterName, clientName, new Partitioner(), loggerFactory);
            State.ShutdownRequested += () =>
            {
                // yes, we are starting a fire-and-forget task
                // but, DisposeAsync should never throw
                // yet we add a CfAwaitNoThrow() for more safety
                DisposeAsync().CfAwaitNoThrow();
            };

            // create components
            _terminateConnections = new TerminateConnections(loggerFactory);
            Members     = new ClusterMembers(State, _terminateConnections);
            Messaging   = new ClusterMessaging(State, Members);
            Events      = new ClusterEvents(State, Messaging, _terminateConnections, Members);
            Connections = new ClusterConnections(State, Members, serializationService);
            _heartbeat  = new Heartbeat(State, Messaging, options.Heartbeat, _terminateConnections);

            // wire components
            WireComponents();

            HConsole.Configure(x => x.Configure <Cluster>().SetIndent(2).SetPrefix("CLUSTER"));
        }
Beispiel #8
0
        private volatile int _disposed; // disposed flag

        /// <summary>
        /// Initializes a new instance of the <see cref="Cluster"/> class.
        /// </summary>
        /// <param name="options">The cluster configuration.</param>
        /// <param name="serializationService">The serialization service.</param>
        /// <param name="loggerFactory">A logger factory.</param>
        public Cluster(
            IClusterOptions options,
            ISerializationService serializationService,
            ILoggerFactory loggerFactory)
        {
            _options = options ?? throw new ArgumentNullException(nameof(options));

            if (serializationService == null)
            {
                throw new ArgumentNullException(nameof(serializationService));
            }
            if (loggerFactory is null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _logger = loggerFactory.CreateLogger <Cluster>();

            DefaultOperationTimeoutMilliseconds = options.Messaging.DefaultOperationTimeoutMilliseconds;
            Partitioner = new Partitioner();

            var loadBalancer = options.LoadBalancing.LoadBalancer.Service ?? new RoundRobinLoadBalancer();

            var clientName = string.IsNullOrWhiteSpace(options.ClientName)
                ? options.ClientNamePrefix + ClusterIdSequence.GetNext()
                : options.ClientName;

            var clusterName = string.IsNullOrWhiteSpace(options.ClusterName) ? "dev" : options.ClusterName;

            _clusterState = new ClusterState(options, clusterName, clientName, Partitioner, loadBalancer, loggerFactory);

            Members       = new ClusterMembers(_clusterState);
            Messaging     = new ClusterMessaging(_clusterState, Members);
            Events        = new ClusterEvents(_clusterState, Messaging, Members);
            ClusterEvents = new ClusterClusterEvents(_clusterState, Members, Events);
            Connections   = new ClusterConnections(_clusterState, ClusterEvents, Events, Members, serializationService, TerminateAsync);

            _heartbeat = new Heartbeat(_clusterState, Members, Messaging, options.Heartbeat, loggerFactory);
            _heartbeat.Start();

            HConsole.Configure(this, config => config.SetIndent(2).SetPrefix("CLUSTER"));
        }
        private volatile int _disposed; // disposed flag

        /// <summary>
        /// Initializes a new instance of the <see cref="Cluster"/> class.
        /// </summary>
        /// <param name="options">The cluster configuration.</param>
        /// <param name="serializationService">The serialization service.</param>
        /// <param name="loggerFactory">A logger factory.</param>
        public Cluster(
            IClusterOptions options,
            SerializationService serializationService,
            ILoggerFactory loggerFactory)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (serializationService == null)
            {
                throw new ArgumentNullException(nameof(serializationService));
            }
            if (loggerFactory is null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _logger = loggerFactory.CreateLogger <Cluster>();

            var clientName = string.IsNullOrWhiteSpace(options.ClientName)
                ? options.ClientNamePrefix + ClusterIdSequence.GetNext()
                : options.ClientName;

            var clusterName = string.IsNullOrWhiteSpace(options.ClusterName) ? "dev" : options.ClusterName;

            State = new ClusterState(options, clusterName, clientName, new Partitioner(), loggerFactory);

            Members       = new ClusterMembers(State);
            Messaging     = new ClusterMessaging(State, Members);
            Events        = new ClusterEvents(State, Messaging, Members);
            ClusterEvents = new ClusterClusterEvents(State, Members, Events);
            Connections   = new ClusterConnections(State, Members, serializationService);

            _heartbeat = new Heartbeat(State, Members, Messaging, options.Heartbeat, loggerFactory);

            HConsole.Configure(x => x.Set(this, config => config.SetIndent(2).SetPrefix("CLUSTER")));
        }
 public ObjectLifecycleEventSubscription(ClusterState clusterState, ClusterEvents clusterEvents)
     : base(clusterState, clusterEvents)
 {
     _isSmart = clusterState.Options.Networking.SmartRouting;
 }
Beispiel #11
0
 protected EventSubscriptionBase(ClusterState clusterState, ClusterEvents clusterEvents)
 {
     LoggerFactory = clusterState.LoggerFactory;
     ClusterEvents = clusterEvents;
 }
 public PartitionLostEventSubscription(ClusterState clusterState, ClusterEvents clusterEvents, ClusterMembers clusterMembers)
     : base(clusterState, clusterEvents)
 {
     _clusterMembers = clusterMembers;
     _isSmart        = clusterState.Options.Networking.SmartRouting;
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="ClusterClusterEvents"/> class.
        /// </summary>
        /// <param name="clusterState">The cluster state.</param>
        /// <param name="clusterMembers">The cluster members.</param>
        /// <param name="clusterEvents">The cluster events.</param>
        public ClusterClusterEvents(ClusterState clusterState, ClusterMembers clusterMembers, ClusterEvents clusterEvents)
        {
            _clusterState = clusterState;

            _objectLifecycleEventSubscription = new ObjectLifecycleEventSubscription(_clusterState, clusterEvents)
            {
                ObjectCreated   = args => _objectCreated.AwaitEach(args),
                ObjectDestroyed = args => _objectDestroyed.AwaitEach(args)
            };

            _partitionLostEventSubscription = new PartitionLostEventSubscription(_clusterState, clusterEvents, clusterMembers)
            {
                PartitionLost = args => _partitionLost.AwaitEach(args)
            };
        }