private void InitializeOnServer(ClientProxy clientProxy)
        {
            var initializationTarget = FindNextAddressToCreateARequest();
            var invocationTarget     = initializationTarget;

            if (initializationTarget != null &&
                _client.GetConnectionManager().GetConnection(initializationTarget) == null)
            {
                invocationTarget = _client.GetClientClusterService().GetOwnerConnectionAddress();
            }

            if (invocationTarget == null)
            {
                throw new IOException("Not able to setup owner connection!");
            }

            var request = ClientCreateProxyCodec.EncodeRequest(clientProxy.GetName(), clientProxy.GetServiceName(),
                                                               initializationTarget);

            try
            {
                ThreadUtil.GetResult(_client.GetInvocationService().InvokeOnTarget(request, invocationTarget));
            }
            catch (Exception e)
            {
                throw ExceptionUtil.Rethrow(e);
            }
        }
        /// <summary>
        /// Gets or creates a distributed object.
        /// </summary>
        /// <typeparam name="T">The type of the distributed object.</typeparam>
        /// <typeparam name="TImpl">The type of the implementation.</typeparam>
        /// <param name="serviceName">The unique name of the service.</param>
        /// <param name="name">The unique name of the object.</param>
        /// <param name="remote">Whether to create the object remotely too.</param>
        /// <param name="factory">The object factory.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>The distributed object.</returns>
        public async Task <T> GetOrCreateAsync <T, TImpl>(
            string serviceName, string name, bool remote,
            Func <string, DistributedObjectFactory, Cluster, SerializationService, ILoggerFactory, TImpl> factory,
            CancellationToken cancellationToken = default)
            where TImpl : DistributedObjectBase, T
        {
            if (_disposed == 1)
            {
                throw new ObjectDisposedException("DistributedObjectFactory");
            }

            var info = new DistributedObjectInfo(serviceName, name);

            async ValueTask <DistributedObjectBase> CreateAsync(DistributedObjectInfo info2, CancellationToken token)
            {
                var x = factory(name, this, _cluster, _serializationService, _loggerFactory);

                x.ObjectDisposed = OnObjectDisposed; // this is why is has to be DistributedObjectBase

                // initialize the object
                if (remote)
                {
                    var requestMessage = ClientCreateProxyCodec.EncodeRequest(x.Name, x.ServiceName);
                    _ = await _cluster.Messaging.SendAsync(requestMessage, token).CfAwait();
                }

                x.OnInitialized();
                _logger.LogDebug("Initialized ({Object}) distributed object.", info2);
                return(x);
            }

            // try to get the object - thanks to the concurrent dictionary there will be only 1 task
            // and if several concurrent requests are made, they will all await that same task

            var o = await _objects.GetOrAddAsync(info, CreateAsync, cancellationToken).CfAwait();

            // race condition: maybe the factory has been disposed and is already disposing
            // objects and will ignore this new object even though it has been added to the
            // dictionary, so take care of it ourselves
            if (_disposed == 1)
            {
                await o.DisposeAsync().CfAwait();

                throw new ObjectDisposedException("DistributedObjectFactory");
            }

            // if the object is a T then we can return it
            if (o is T t)
            {
                return(t);
            }

            // otherwise, the client was already used to retrieve an object with the specified service
            // name and object name, but a different type, for instance IHList<int> vs IHList<string>,
            // and we just cannot support this = throw

            throw new HazelcastException($"A distributed object with the specified service name ({serviceName}) " +
                                         $"and object name ({name}) exists but of type {o.GetType().ToCsString()}, " +
                                         $"instead of {typeof(T).ToCsString()}.");
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets or creates a distributed object.
        /// </summary>
        /// <typeparam name="T">The type of the distributed object.</typeparam>
        /// <typeparam name="TImpl">The type of the implementation.</typeparam>
        /// <param name="serviceName">The unique name of the service.</param>
        /// <param name="name">The unique name of the object.</param>
        /// <param name="remote">Whether to create the object remotely too.</param>
        /// <param name="factory">The object factory.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>The distributed object.</returns>
        public async Task <T> GetOrCreateAsync <T, TImpl>(
            string serviceName, string name, bool remote,
            Func <string, DistributedObjectFactory, Cluster, ISerializationService, ILoggerFactory, TImpl> factory,
            CancellationToken cancellationToken = default)
            where TImpl : DistributedObjectBase, T
        {
            if (_disposed == 1)
            {
                throw new ObjectDisposedException("DistributedObjectFactory");
            }
            await _cluster.ThrowIfNotConnected().CAF();

            var k = new DistributedObjectInfo(serviceName, name);

            async ValueTask <DistributedObjectBase> CreateAsync(DistributedObjectInfo info, CancellationToken token)
            {
                var x = factory(name, this, _cluster, _serializationService, _loggerFactory);

                x.OnDispose = ObjectDisposed; // this is why is has to be DistributedObjectBase

                // initialize the object
                if (remote)
                {
                    var requestMessage = ClientCreateProxyCodec.EncodeRequest(x.Name, x.ServiceName);
                    _ = await _cluster.Messaging.SendAsync(requestMessage, token).CAF();
                }

                x.OnInitialized();
                _logger.LogDebug("Initialized '{ServiceName}/{Name}' distributed object.", info.ServiceName, info.Name);
                return(x);
            }

            // try to get the object - thanks to the concurrent dictionary there will be only 1 task
            // and if several concurrent requests are made, they will all await that same task

            var o = await _objects.GetOrAddAsync(k, CreateAsync, cancellationToken).CAF();

            // race condition: maybe the factory has been disposed and is already disposing
            // objects and will ignore this new object even though it has been added to the
            // dictionary, so take care of it ourselves
            if (_disposed == 1)
            {
                await o.DisposeAsync().CAF();

                throw new ObjectDisposedException("DistributedObjectFactory");
            }

            if (o is T t)
            {
                return(t);
            }

            // if the object that was retrieved is not of the right type, it's a problem
            // preserve the existing object, but throw
            throw new InvalidCastException("A distributed object with the specified service name and name, but "
                                           + "with a different type, has already been created.");
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates all known <see cref="IDistributedObject"/> on a cluster.
        /// </summary>
        /// <returns>A task that will complete when the state has been sent.</returns>
        /// <remarks>
        /// <para>This is used when connecting to a new cluster.</para>
        /// </remarks>
        public async ValueTask CreateAllAsync(CancellationToken cancellationToken)
        {
            await foreach (var(key, _) in _objects)
            {
                // if the cluster goes down, we want to stop everything
                // but each invocation is non-cancellable
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var requestMessage = ClientCreateProxyCodec.EncodeRequest(key.Name, key.ServiceName);
                    await _cluster.Messaging.SendAsync(requestMessage, cancellationToken).CfAwait();
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Failed to create ({key}) distributed object on new cluster.");
                }
            }
        }
        /// <summary>
        /// Creates all known <see cref="IDistributedObject"/> on a cluster.
        /// </summary>
        /// <returns>A task that will complete when the state has been sent.</returns>
        /// <remarks>
        /// <para>This is used when connecting to a new cluster.</para>
        /// </remarks>
        public async ValueTask CreateAllAsync(MemberConnection connection)
        {
            await foreach (var(key, _) in _objects)
            {
                // if the connection goes down, stop
                if (!connection.Active)
                {
                    return;
                }

                try
                {
                    var requestMessage = ClientCreateProxyCodec.EncodeRequest(key.Name, key.ServiceName);
                    await _cluster.Messaging.SendToMemberAsync(requestMessage, connection).CfAwait();
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Failed to create ({key}) distributed object on new cluster.");
                }
            }
        }
        private void Initialize(ClientProxy clientProxy)
        {
            var request = ClientCreateProxyCodec.EncodeRequest(clientProxy.Name, clientProxy.ServiceName);

            ThreadUtil.GetResult(_client.InvocationService.InvokeOnRandomTarget(request));
        }