/// <summary> /// Configure silo to use indexing using a configure action. /// </summary> public static ISiloHostBuilder UseIndexing(this ISiloHostBuilder builder, Action <IndexingOptions> configureOptions = null) { // This is necessary to get the configured NumWorkflowQueuesPerInterface for IndexFactory.RegisterIndexWorkflowQueueGrainServices. var indexingOptions = new IndexingOptions(); configureOptions?.Invoke(indexingOptions); return(builder.AddSimpleMessageStreamProvider(IndexingConstants.INDEXING_STREAM_PROVIDER_NAME) .AddMemoryGrainStorage(IndexingConstants.INDEXING_WORKFLOWQUEUE_STORAGE_PROVIDER_NAME) .AddMemoryGrainStorage(IndexingConstants.INDEXING_STORAGE_PROVIDER_NAME) .AddMemoryGrainStorage(IndexingConstants.MEMORY_STORAGE_PROVIDER_NAME) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(SiloBuilderExtensions).Assembly)) .ConfigureServices(services => services.UseIndexing(indexingOptions)) .ConfigureServices((context, services) => ApplicationPartsIndexableGrainLoader.RegisterGrainServices(context, services, indexingOptions)) .UseTransactions()); }
/// <summary> /// Configure silo services to use indexing using a configuration builder. /// </summary> private static IServiceCollection UseIndexing(this IServiceCollection services, IndexingOptions indexingOptions) { services.AddOptions <IndexingOptions>(IndexingConstants.INDEXING_OPTIONS_NAME).Configure(options => options.ShallowCopyFrom(indexingOptions)); services.AddSingleton <IndexFactory>() .AddFromExisting <IIndexFactory, IndexFactory>(); services.AddSingleton <SiloIndexManager>() .AddFromExisting <ILifecycleParticipant <ISiloLifecycle>, SiloIndexManager>(); services.AddFromExisting <IndexManager, SiloIndexManager>(); // Facet Factory and Mappers services.AddTransient <IIndexedStateFactory, IndexedStateFactory>() .AddSingleton(typeof(IAttributeToFactoryMapper <NonFaultTolerantWorkflowIndexedStateAttribute>), typeof(NonFaultTolerantWorkflowIndexedStateAttributeMapper)) .AddSingleton(typeof(IAttributeToFactoryMapper <FaultTolerantWorkflowIndexedStateAttribute>), typeof(FaultTolerantWorkflowIndexedStateAttributeMapper)) .AddSingleton(typeof(IAttributeToFactoryMapper <TransactionalIndexedStateAttribute>), typeof(TransactionalIndexedStateAttributeMapper)); return(services); }
/// <summary> /// This method crawls the assemblies and looks for the index definitions (determined by extending the <see cref="IIndexableGrain{TProperties}"/> /// interface and adding annotations to properties in TProperties), and registers the grain services needed for queues and PerSilo partitioning. /// </summary> /// <remarks>This two-step approach (RegisterGrainServices and then CreateIndexRegistry) is necessary because GrainServices should be /// registered to the IServiceCollection before Silo construction and the rest of Index creation requires the IServiceProvider which /// is created as part of Silo construction.</remarks> /// <returns>An index registry for the silo. </returns> internal static void RegisterGrainServices(HostBuilderContext context, IServiceCollection services, IndexingOptions indexingOptions) { var indexedClasses = new HashSet <Type>(); var indexedInterfaces = new HashSet <Type>(); foreach (var grainClassType in GetIndexedConcreteGrainClasses(context.GetApplicationPartManager())) { var consistencyScheme = grainClassType.GetConsistencyScheme(); if (consistencyScheme == ConsistencyScheme.Transactional) { continue; } var indexedInterfacesAndProperties = EnumerateIndexedInterfacesForAGrainClassType(grainClassType).ToList(); foreach (var(grainInterfaceType, propertiesClassType) in indexedInterfacesAndProperties) { if (indexedInterfaces.Contains(grainInterfaceType)) { continue; } indexedInterfaces.Add(grainInterfaceType); var createQueues = consistencyScheme != ConsistencyScheme.Transactional; foreach (var propInfo in propertiesClassType.GetProperties()) { var indexName = IndexUtils.PropertyNameToIndexName(propInfo.Name); var indexAttrs = propInfo.GetCustomAttributes <IndexAttribute>(inherit: false); foreach (var indexAttr in indexAttrs) { if (createQueues && !(bool)isEagerProperty.GetValue(indexAttr)) { // Queues are per-interface, not per-index. IndexFactory.RegisterIndexWorkflowQueueGrainServices(services, grainInterfaceType, indexingOptions, consistencyScheme == ConsistencyScheme.FaultTolerantWorkflow); } createQueues = false; var indexType = (Type)indexTypeProperty.GetValue(indexAttr); var regMethod = indexType.GetCustomAttribute <PerSiloIndexGrainServiceClassAttribute>(inherit: false) ?.GrainServiceClassType ?.GetMethod("RegisterGrainService", BindingFlags.Static | BindingFlags.NonPublic); if (regMethod != null) // Static method so cannot use an interface { var regDelegate = (Action <IServiceCollection, Type, string>)Delegate.CreateDelegate(typeof(Action <IServiceCollection, Type, string>), regMethod); regDelegate(services, grainInterfaceType, indexName); } } } } } }
internal static void RegisterIndexWorkflowQueueGrainServices(IServiceCollection services, Type grainInterfaceType, IndexingOptions indexingOptions, bool isFaultTolerant) { for (int i = 0; i < indexingOptions.NumWorkflowQueuesPerInterface; ++i) { var seq = i; // Captured by the lambda services.AddGrainService(sp => new IndexWorkflowQueueGrainService(sp.GetRequiredService <SiloIndexManager>(), grainInterfaceType, seq, isFaultTolerant)); services.AddGrainService(sp => new IndexWorkflowQueueHandlerGrainService(sp.GetRequiredService <SiloIndexManager>(), grainInterfaceType, seq, isFaultTolerant)); } }