Пример #1
0
        /// <summary>
        /// If activation already exists, use it
        /// Otherwise, create an activation of an existing grain by reading its state.
        /// Return immediately using a dummy that will queue messages.
        /// Concurrently start creating and initializing the real activation and replace it when it is ready.
        /// </summary>
        /// <param name="address">Grain's activation address</param>
        /// <param name="requestContextData">Request context data.</param>
        /// <returns></returns>
        public IGrainContext GetOrCreateActivation(
            GrainAddress address,
            Dictionary <string, object> requestContextData)
        {
            if (TryGetGrainContext(address.GrainId, out var result))
            {
                return(result);
            }

            // Lock over all activations to try to prevent multiple instances of the same activation being created concurrently.
            lock (activations)
            {
                if (TryGetGrainContext(address.GrainId, out result))
                {
                    return(result);
                }

                if (!SiloStatusOracle.CurrentStatus.IsTerminating())
                {
                    result = this.grainActivator.CreateInstance(address);
                    RegisterMessageTarget(result);
                }
            } // End lock

            if (result is null)
            {
                // Did not find and did not start placing new
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.LogDebug((int)ErrorCode.CatalogNonExistingActivation2, "Non-existent activation {Activation}", address.ToFullString());
                }

                CounterStatistic.FindOrCreate(StatisticNames.CATALOG_ACTIVATION_NON_EXISTENT_ACTIVATIONS).Increment();

                this.directory.InvalidateCacheEntry(address);

                // Unregister the target activation so we don't keep getting spurious messages.
                // The time delay (one minute, as of this writing) is to handle the unlikely but possible race where
                // this request snuck ahead of another request, with new placement requested, for the same activation.
                // If the activation registration request from the new placement somehow sneaks ahead of this unregistration,
                // we want to make sure that we don't unregister the activation we just created.
                _ = this.UnregisterNonExistentActivation(address);
                return(null);
            }
            else
            {
                // Initialize the new activation asynchronously.
                var cancellation = new CancellationTokenSource(collectionOptions.Value.ActivationTimeout);
                result.Activate(requestContextData, cancellation.Token);
                return(result);
            }
        }