예제 #1
0
        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;
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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;
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        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;
            }
        }
예제 #9
0
        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);
            }
        }
예제 #10
0
        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);
        }
예제 #11
0
        /// <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);
                    }
                }
            }
        }
예제 #12
0
 public DocumentDbInitialiser(DocumentClient client, DocumentDbConfig config)
 {
     _client = client;
     _config = config;
 }
예제 #13
0
 public AzureDocClient(DocumentDbConfig documentDbConfig)
 {
     _documentDbConfig = documentDbConfig;
 }
예제 #14
0
 /// <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));
 }
예제 #15
0
        /// <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);
        }
예제 #16
0
 private Uri GetDocumentCollectionUri(DocumentDbConfig dbConfig)
 {
     return(UriFactory.CreateDocumentCollectionUri(dbConfig.DatabaseId, dbConfig.CollectionName));
 }
예제 #17
0
 public AzureDocDatabase(IAzureDocClient docClient, DocumentDbConfig documentDbConfig)
 {
     _docClient        = docClient;
     _documentDbConfig = documentDbConfig;
 }