-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy pathDatabaseSetup.cs
More file actions
129 lines (106 loc) · 6.04 KB
/
DatabaseSetup.cs
File metadata and controls
129 lines (106 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
namespace ServiceControl.Audit.Persistence.RavenDB;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Raven.Client.Documents;
using Raven.Client.Documents.Indexes;
using Raven.Client.Documents.Operations.Expiration;
using Raven.Client.Documents.Operations.Indexes;
using Raven.Client.Exceptions;
using Raven.Client.ServerWide;
using Raven.Client.ServerWide.Operations;
using Raven.Client.ServerWide.Operations.Configuration;
using Indexes;
using SagaAudit;
class DatabaseSetup(DatabaseConfiguration configuration)
{
public async Task Execute(IDocumentStore documentStore, CancellationToken cancellationToken)
{
await CreateDatabase(documentStore, configuration.Name, cancellationToken);
await UpdateDatabaseSettings(documentStore, configuration.Name, cancellationToken);
await CreateIndexes(documentStore, configuration.EnableFullTextSearch, cancellationToken);
await LicenseStatusCheck.WaitForLicenseOrThrow(documentStore, cancellationToken);
await ConfigureExpiration(documentStore, cancellationToken);
}
async Task CreateDatabase(IDocumentStore documentStore, string databaseName, CancellationToken cancellationToken)
{
var dbRecord = await documentStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName), cancellationToken);
if (dbRecord is null)
{
try
{
var databaseRecord = new DatabaseRecord(databaseName);
SetSearchEngineType(databaseRecord, SearchEngineType.Corax);
await documentStore.Maintenance.Server.SendAsync(new CreateDatabaseOperation(databaseRecord), cancellationToken);
}
catch (ConcurrencyException)
{
// The database was already created before calling CreateDatabaseOperation
}
}
}
async Task UpdateDatabaseSettings(IDocumentStore documentStore, string databaseName, CancellationToken cancellationToken)
{
var databaseRecord = await documentStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName), cancellationToken) ?? throw new InvalidOperationException($"Database '{databaseName}' does not exist.");
if (!SetSearchEngineType(databaseRecord, SearchEngineType.Corax))
{
return;
}
await documentStore.Maintenance.ForDatabase(databaseName).SendAsync(new PutDatabaseSettingsOperation(databaseName, databaseRecord.Settings), cancellationToken);
await documentStore.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, true), cancellationToken);
await documentStore.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, false), cancellationToken);
}
public static async Task DeleteLegacySagaDetailsIndex(IDocumentStore documentStore, CancellationToken cancellationToken)
{
// If the SagaDetailsIndex exists but does not have a .Take(50000), then we remove the current SagaDetailsIndex and
// create a new one. If we do not remove the current one, then RavenDB will attempt to do a side-by-side migration.
// Doing a side-by-side migration results in the index never swapping if there is constant ingestion as RavenDB will wait.
// for the index to not be stale before swapping to the new index. Constant ingestion means the index will never be not-stale.
// This needs to stay in place until the next major version as the user could upgrade from an older version of the current
// Major (v5.x.x) which might still have the incorrect index.
var sagaDetailsIndexOperation = new GetIndexOperation(SagaDetailsIndexName);
var sagaDetailsIndexDefinition = await documentStore.Maintenance.SendAsync(sagaDetailsIndexOperation, cancellationToken);
if (sagaDetailsIndexDefinition != null && !sagaDetailsIndexDefinition.Reduce.Contains("Take(50000)"))
{
await documentStore.Maintenance.SendAsync(new DeleteIndexOperation(SagaDetailsIndexName), cancellationToken);
}
}
internal static async Task CreateIndexes(IDocumentStore documentStore, bool enableFreeTextSearch, CancellationToken cancellationToken)
{
await DeleteLegacySagaDetailsIndex(documentStore, cancellationToken);
List<AbstractIndexCreationTask> indexList = [new FailedAuditImportIndex(), new SagaDetailsIndex()];
if (enableFreeTextSearch)
{
indexList.Add(new MessagesViewIndexWithFullTextSearch());
await documentStore.Maintenance.SendAsync(new DeleteIndexOperation(MessagesViewIndexName), cancellationToken);
}
else
{
indexList.Add(new MessagesViewIndex());
await documentStore.Maintenance.SendAsync(new DeleteIndexOperation(MessagesViewIndexWithFulltextSearchName), cancellationToken);
}
await IndexCreation.CreateIndexesAsync(indexList, documentStore, null, null, cancellationToken);
}
async Task ConfigureExpiration(IDocumentStore documentStore, CancellationToken cancellationToken)
{
var expirationConfig = new ExpirationConfiguration
{
Disabled = false,
DeleteFrequencyInSec = configuration.ExpirationProcessTimerInSeconds
};
await documentStore.Maintenance.SendAsync(new ConfigureExpirationOperation(expirationConfig), cancellationToken);
}
bool SetSearchEngineType(DatabaseRecord database, SearchEngineType searchEngineType)
{
var updated = false;
updated |= database.Settings.TryAdd("Indexing.Auto.SearchEngineType", searchEngineType.ToString());
updated |= database.Settings.TryAdd("Indexing.Static.SearchEngineType", searchEngineType.ToString());
return updated;
}
internal const string MessagesViewIndexWithFulltextSearchName = "MessagesViewIndexWithFullTextSearch";
internal const string SagaDetailsIndexName = "SagaDetailsIndex";
internal const string MessagesViewIndexName = "MessagesViewIndex";
}