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(); } }
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 }
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(); } }
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")); }
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; }
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) }; }