Skip to content

Commit 96cdbfb

Browse files
committed
Add command to flush buckets
1 parent 2869919 commit 96cdbfb

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

src/Couchbase.Aspire.Hosting/Api/CouchbaseApi.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,20 @@ public async Task<SampleBucketResponse> CreateSampleBucketAsync(CouchbaseServerR
321321
return (await response.Content.ReadFromJsonAsync<SampleBucketResponse>(cancellationToken).ConfigureAwait(false))!;
322322
}
323323

324+
public async Task FlushBucketAsync(CouchbaseServerResource server, string bucketName,
325+
CancellationToken cancellationToken = default)
326+
{
327+
ArgumentNullException.ThrowIfNull(server);
328+
ArgumentException.ThrowIfNullOrEmpty(bucketName);
329+
330+
var response = await SendRequestAsync(server.GetManagementEndpoint(),
331+
HttpMethod.Post,
332+
$"/pools/default/buckets/{bucketName}/controller/doFlush",
333+
cancellationToken: cancellationToken).ConfigureAwait(false);
334+
335+
await ThrowOnFailureAsync(response, cancellationToken).ConfigureAwait(false);
336+
}
337+
324338
public async Task<List<ClusterTask>> GetClusterTasksAsync(CouchbaseServerResource server, CancellationToken cancellationToken)
325339
{
326340
ArgumentNullException.ThrowIfNull(server);

src/Couchbase.Aspire.Hosting/Api/ICouchbaseApi.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ internal interface ICouchbaseApi
77
Task CreateBucketAsync(CouchbaseServerResource server, string bucketName, CouchbaseBucketSettings settings, CancellationToken cancellationToken = default);
88
Task<SampleBucketResponse> CreateSampleBucketAsync(CouchbaseServerResource server, string bucketName, CancellationToken cancellationToken);
99
Task<Bucket?> GetBucketAsync(CouchbaseServerResource server, string bucketName, CancellationToken cancellationToken);
10+
Task FlushBucketAsync(CouchbaseServerResource server, string bucketName, CancellationToken cancellationToken);
1011
Task<Pool> GetClusterNodesAsync(CouchbaseServerResource server, CancellationToken cancellationToken = default);
1112
Task<bool> GetDefaultPoolAsync(CouchbaseServerResource server, bool preferInsecure = false, CancellationToken cancellationToken = default);
1213
Task<RebalanceStatus> GetRebalanceProgressAsync(CouchbaseServerResource server, CancellationToken cancellationToken = default);

src/Couchbase.Aspire.Hosting/CouchbaseBucketBuilderExtensions.cs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Aspire.Hosting;
22
using Aspire.Hosting.ApplicationModel;
33
using Couchbase.Aspire.Hosting;
4+
using Couchbase.Aspire.Hosting.Api;
45
using Couchbase.KeyValue;
56
using Couchbase.Management.Buckets;
67
using Microsoft.Extensions.DependencyInjection;
@@ -207,11 +208,78 @@ public static IResourceBuilder<CouchbaseBucketResource> WithFlushEnabled(this IR
207208
{
208209
ArgumentNullException.ThrowIfNull(builder);
209210

210-
return builder.WithSettings(context =>
211+
builder.WithSettings(context =>
211212
{
212213
context.Settings.FlushEnabled = enabled;
213214
return Task.CompletedTask;
214215
});
216+
217+
const string flushCommandName = "flush-bucket";
218+
if (enabled ?? false)
219+
{
220+
// Add a command to flush the bucket
221+
builder.WithCommand(flushCommandName, "Flush",
222+
async (context) =>
223+
{
224+
var apiService = context.ServiceProvider.GetRequiredService<ICouchbaseApiService>();
225+
var api = apiService.GetApi(builder.Resource.Parent);
226+
227+
var server = builder.Resource.Parent.GetPrimaryServer();
228+
if (server is null)
229+
{
230+
return new ExecuteCommandResult
231+
{
232+
Success = false,
233+
ErrorMessage = "No available server to flush the bucket."
234+
};
235+
}
236+
237+
await api.FlushBucketAsync(server, builder.Resource.BucketName, context.CancellationToken).ConfigureAwait(false);
238+
239+
// Wait for bucket to be healthy
240+
while (true)
241+
{
242+
context.CancellationToken.ThrowIfCancellationRequested();
243+
244+
var bucketInfo = await api.GetBucketAsync(server, builder.Resource.BucketName, context.CancellationToken).ConfigureAwait(false);
245+
if (bucketInfo?.Nodes?.All(p => p.Status == BucketNode.HealthyStatus) ?? false)
246+
{
247+
break;
248+
}
249+
250+
await Task.Delay(250, context.CancellationToken).ConfigureAwait(false);
251+
}
252+
253+
return new ExecuteCommandResult { Success = true };
254+
},
255+
new CommandOptions
256+
{
257+
UpdateState = context =>
258+
{
259+
var state = context.ResourceSnapshot.State?.Text;
260+
return state == KnownResourceStates.Running
261+
? ResourceCommandState.Enabled
262+
: ResourceCommandState.Hidden;
263+
},
264+
IconName = "DeleteLines",
265+
IsHighlighted = true,
266+
ConfirmationMessage = $"Flushing bucket '{builder.Resource.BucketName}', are you sure?",
267+
});
268+
}
269+
else
270+
{
271+
// Remove the command if it was previously added
272+
var existingCommand = builder.Resource.Annotations
273+
.OfType<ResourceCommandAnnotation>()
274+
.FirstOrDefault(p => p.Name == flushCommandName);
275+
276+
if (existingCommand is not null)
277+
{
278+
builder.Resource.Annotations.Remove(existingCommand);
279+
}
280+
}
281+
282+
return builder;
215283
}
216284

217285
/// <summary>

0 commit comments

Comments
 (0)