private async Task StoreConfigRecordAsync( IDocumentClient client, DocumentDbConfig dbConfig, ServiceConfigRecord newRecord, Document existingDocument) { var collectionUri = GetDocumentCollectionUri(dbConfig); if (existingDocument == null) { // No record exists yet. Use the creation method to ensure failure if another process has modified the // record that a failure is produced. await client.CreateDocumentAsync(collectionUri, newRecord); } else { // Add IfMatch header to ensure the record has not been changed by another process. RequestOptions options = new RequestOptions { AccessCondition = new AccessCondition { Condition = existingDocument.ETag, Type = AccessConditionType.IfMatch } }; await client.UpsertDocumentAsync(collectionUri, newRecord, options); } }
private async Task EnsureCurrent(IDocumentClient client, DocumentDbConfig dbConfig) { List <DocumentStoreConfig> stores; lock (_sync) { // Return early if no service update is required. if (!_serviceUpdateRequired) { return; } stores = _configSources.Values.Select(x => x.GetConfig()).ToList(); } var configSignature = CreateSignature(stores); try { await EnsureServiceConfigAsync(client, dbConfig, configSignature, stores); } catch (DocumentClientException e) { throw new NebulaConfigException("Failed to update service configuration due to document client error", e); } catch (Exception e) { throw new NebulaConfigException("Failed to update service configuration", e); } // Service update successful. _serviceUpdateRequired = false; }
/// <summary> /// Initialises a new instance of the <see cref="DocumentDbService"/> class. /// </summary> /// <param name="configManager">The service config manager.</param> /// <param name="dbConfig">The document db config.</param> public DocumentDbService(ServiceDbConfigManager configManager, DocumentDbConfig dbConfig) { if (configManager == null) { throw new ArgumentNullException(nameof(configManager)); } if (dbConfig == null) { throw new ArgumentNullException(nameof(dbConfig)); } _configManager = configManager; _dbConfig = dbConfig; var connectionPolicy = new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp, RetryOptions = new RetryOptions { MaxRetryAttemptsOnThrottledRequests = 20, MaxRetryWaitTimeInSeconds = 60 } }; _client = new DocumentClient(new Uri(dbConfig.ServiceEndpoint), dbConfig.AuthKey, connectionPolicy); }
/// <summary> /// Initializes a new instance of the <see cref="DocumentDbService"/> class. /// </summary> /// <param name="keyVaultService">Key Vault Service</param> /// <param name="config">Config</param> public DocumentDbService(IKeyVaultService keyVaultService, IOptions <DocumentDbConfig> config) { Contract.Requires(config != null, nameof(config)); Contract.Requires(keyVaultService != null, nameof(keyVaultService)); this.config = config.Value; this.keyVaultService = keyVaultService; }
internal void EnsureConfigCurrent(IDocumentClient client, DocumentDbConfig dbConfig) { if (client == null) { throw new ArgumentNullException(nameof(client)); } if (dbConfig == null) { throw new ArgumentNullException(nameof(dbConfig)); } EnsureCurrent(client, dbConfig); }
private async Task UpdateCollectionConfigAsync(IDocumentClient client, DocumentDbConfig dbConfig, List <DocumentStoreConfig> storeConfigs) { DocumentCollection collection = await client.ReadDocumentCollectionAsync(GetDocumentCollectionUri(dbConfig)); RemoveIndexes(collection); AddIndexes(collection, storeConfigs); var requestOptions = new RequestOptions(); requestOptions.AccessCondition = new AccessCondition { Type = AccessConditionType.IfMatch, Condition = collection.ETag }; await client.ReplaceDocumentCollectionAsync(collection, requestOptions); }
/// <summary> /// Initialises a new instance of the <see cref="DocumentDbService"/> class. /// </summary> /// <param name="dbConfig">The document db config.</param> public DocumentDbService(DocumentDbConfig dbConfig) { if (dbConfig == null) { throw new ArgumentNullException(nameof(dbConfig)); } _dbConfig = dbConfig; var connectionPolicy = new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp }; _client = new DocumentClient(new Uri(dbConfig.ServiceEndpoint), dbConfig.AuthKey, connectionPolicy); }
private void EnsureCurrent(IDocumentClient client, DocumentDbConfig dbConfig) { // This processing must be synchronised to ensure that service updates are kept consistent. See further // commentary in RegisterSource. List <DocumentStoreConfig> stores; lock (_sync) { // Return early if no service update is required. if (!_serviceUpdateRequired) { return; } stores = _configSources.Values.Select(x => x.GetConfig()).ToList(); } var configSignature = CreateSignature(stores); lock (_sync) { try { EnsureServiceConfigAsync(client, dbConfig, configSignature, stores).Wait(); } catch (AggregateException e) { foreach (var exception in e.Flatten().InnerExceptions) { if (exception is DocumentClientException) { throw new NebulaConfigException("Failed to update service configuration due to document client error", e); } } throw new NebulaConfigException("Failed to update service configuration", e.Flatten()); } // Service update successful. _serviceUpdateRequired = false; } }
private async Task <Document> GetConfigRecordAsync(IDocumentClient client, DocumentDbConfig dbConfig) { var configRecordId = GetConfigRecordId(); var documentUri = UriFactory.CreateDocumentUri(dbConfig.DatabaseId, dbConfig.CollectionName, configRecordId); // The collection is partitioned and the config record is not excluded from that requirement. The partition // key is simply set as the config record id. var requestOptions = new RequestOptions { PartitionKey = new PartitionKey(configRecordId) }; try { return(await client.ReadDocumentAsync(documentUri, requestOptions)); } catch (DocumentClientException e) when(e.StatusCode == HttpStatusCode.NotFound) { // Document not found. return(null); } }
private async Task EnsureServiceConfigAsync( IDocumentClient client, DocumentDbConfig dbConfig, string configSignature, List <DocumentStoreConfig> configs) { var existingDocument = await GetConfigRecordAsync(client, dbConfig); if (existingDocument != null) { // Config already exists. ServiceConfigRecord existingConfigRecord = (dynamic)existingDocument; if (existingConfigRecord.Signature == configSignature) { // No changes to the config. Nothing to do. return; } // Config has been updated. Perform an update. await UpdateCollectionConfigAsync(client, dbConfig, configs); } // There has been a config change. Update the config record. var configRecordId = GetConfigRecordId(); var configRecord = new ServiceConfigRecord { Id = configRecordId, Signature = configSignature, PartitionKey = configRecordId }; // Update the store config record. await StoreConfigRecordAsync(client, dbConfig, configRecord, existingDocument); }
/// <summary> /// Configures the document database. /// </summary> /// <param name="documentDbConfig">The document database configuration.</param> /// <param name="allowUpdate">if set to <c>true</c> [allow update].</param> /// <returns> /// The Result /// </returns> /// <exception cref="ArgumentNullException">Document database config</exception> public async Task ConfigureDocumentDb(DocumentDbConfig documentDbConfig, bool allowUpdate) { if (documentDbConfig == null) { this.logger.Error("Invalid Document Db Config"); throw new ArgumentNullException(nameof(documentDbConfig)); } await this.InitializeDocumentClientAsync().ConfigureAwait(false); foreach (var db in documentDbConfig.Databases) { var database = await this.CreateDatabaseAsync(db.Name).ConfigureAwait(false); if (database != null) { foreach (var coll in db.Collections) { var collection = await this.CreateCollectionAsync(database, coll, allowUpdate).ConfigureAwait(false); if (collection != null) { foreach (var item in coll.StoredProcedures) { await this.ImportStoreProcedureAsync(collection, item, allowUpdate).ConfigureAwait(false); } } } foreach (var user in db.Users) { await this.CreateUserAsync(database, user, allowUpdate).ConfigureAwait(false); } } } }
public DocumentDbInitialiser(DocumentClient client, DocumentDbConfig config) { _client = client; _config = config; }
public AzureDocClient(DocumentDbConfig documentDbConfig) { _documentDbConfig = documentDbConfig; }
/// <summary> /// Configures the document database. /// </summary> /// <param name="documentDbConfig">The document database configuration.</param> /// <returns>The Task that configures document database</returns> public Task ConfigureDocumentDb(DocumentDbConfig documentDbConfig) { return(this.ConfigureDocumentDb(documentDbConfig, true)); }
/// <summary> /// Adds Nebula services to the specified <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />. /// </summary> /// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> to add services to.</param> /// <param name="serviceName">The service name.</param> /// <param name="config">The document config.</param> /// <returns>The service collection.</returns> public static IServiceCollection AddNebula(this IServiceCollection services, string serviceName, DocumentDbConfig config) { if (services == null) { throw new ArgumentNullException(nameof(services)); } if (serviceName == null) { throw new ArgumentNullException(nameof(serviceName)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } services.TryAdd(ServiceDescriptor.Singleton <IDocumentDbAccessFactory, StandardDbAccessFactory>( provider => new StandardDbAccessFactory(serviceName, config))); services.TryAddSingleton <IDocumentDbAccessProvider, DocumentDbAccessProvider>(); services.AddHttpContextAccessor(); services.TryAddScoped <IDocumentMetadataSource, DocumentMetadataSource>(); return(services); }
private Uri GetDocumentCollectionUri(DocumentDbConfig dbConfig) { return(UriFactory.CreateDocumentCollectionUri(dbConfig.DatabaseId, dbConfig.CollectionName)); }
public AzureDocDatabase(IAzureDocClient docClient, DocumentDbConfig documentDbConfig) { _docClient = docClient; _documentDbConfig = documentDbConfig; }