Skip to content

Commit 2efcb02

Browse files
committed
Stub AzureBlob health+lifecycle rule updater
1 parent cd3fd56 commit 2efcb02

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Azure.Storage.Blobs;
2+
using Imazen.Abstractions.BlobCache;
3+
using Microsoft.Extensions.Logging;
4+
5+
namespace Imageflow.Server.Storage.AzureBlob.Caching;
6+
7+
internal record HealthCheck(IBlobCache Cache, NamedCacheConfiguration Config, ILogger Logger, Dictionary<BlobGroup, BlobServiceClient> ServiceClients,
8+
ContainerExistenceCache ContainerExists)
9+
{
10+
11+
// this.InitialCacheCapabilities = new BlobCacheCapabilities
12+
// {
13+
// CanFetchMetadata = true,
14+
// CanFetchData = true,
15+
// CanConditionalFetch = false,
16+
// CanPut = true,
17+
// CanConditionalPut = false,
18+
// CanDelete = false,
19+
// CanSearchByTag = false,
20+
// CanPurgeByTag = false,
21+
// CanReceiveEvents = false,
22+
// SupportsHealthCheck = false,
23+
// SubscribesToRecentRequest = false,
24+
// SubscribesToExternalHits = true,
25+
// SubscribesToFreshResults = true,
26+
// RequiresInlineExecution = false,
27+
// FixedSize = false
28+
// };
29+
//
30+
31+
public ValueTask<IBlobCacheHealthDetails> CacheHealthCheck(CancellationToken cancellationToken = default)
32+
{
33+
34+
}
35+
36+
internal record BasicHealthDetails(bool CanFetchData, bool CanFetchMetadata, bool CanConditionalFetch, bool CanPut, bool CanConditionalPut, bool CanSearchByTag, bool CanPurgeByTag);
37+
38+
internal ValueTask<BasicHealthDetails> CheckGroup(BlobGroup group, CancellationToken cancellationToken = default)
39+
{
40+
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using Azure.Storage.Blobs;
2+
using Azure.Storage.Blobs.Models;
3+
using Imazen.Common.Concurrency;
4+
using Microsoft.Extensions.Logging;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Threading.Tasks;
9+
using Imazen.Abstractions.Logging;
10+
using Imazen.Abstractions.Resulting;
11+
12+
namespace Imageflow.Server.Storage.AzureBlob.Caching
13+
{
14+
internal class LifecycleRuleUpdater
15+
{
16+
private readonly NamedCacheConfiguration config;
17+
private readonly IReLogger logger;
18+
private readonly BlobServiceClient defaultClient;
19+
private readonly BasicAsyncLock updateLock = new BasicAsyncLock();
20+
private bool updateComplete = false;
21+
22+
public LifecycleRuleUpdater(NamedCacheConfiguration config, BlobServiceClient defaultClient, IReLogger logger)
23+
{
24+
this.config = config;
25+
this.logger = logger.WithSubcategory(nameof(LifecycleRuleUpdater));
26+
this.defaultClient = defaultClient;
27+
}
28+
29+
internal async Task UpdateIfIncompleteAsync()
30+
{
31+
if (updateComplete) return;
32+
33+
using (await updateLock.LockAsync())
34+
{
35+
if (updateComplete) return;
36+
await CreateContainersAsync();
37+
await UpdateLifecycleRulesAsync();
38+
await CreateAndReadTestFilesAsync(false);
39+
updateComplete = true;
40+
}
41+
}
42+
43+
internal async Task CreateContainersAsync()
44+
{
45+
// Implementation similar to S3LifecycleUpdater's CreateBucketsAsync
46+
// Use BlobServiceClient to create containers if they don't exist
47+
}
48+
49+
internal async Task UpdateLifecycleRulesAsync()
50+
{
51+
var client = defaultClient;
52+
var lifecycleManagementPolicy = new BlobLifecycleManagementPolicy();
53+
var rules = new List<BlobLifecycleRule>();
54+
55+
foreach (var groupConfig in config.BlobGroupConfigurations.Values)
56+
{
57+
if (groupConfig.UpdateLifecycleRules == false) continue;
58+
59+
var containerName = groupConfig.Location.ContainerName;
60+
var prefix = groupConfig.Location.BlobPrefix;
61+
62+
if (groupConfig.Lifecycle.DaysBeforeExpiry.HasValue)
63+
{
64+
var rule = new BlobLifecycleRule
65+
{
66+
Name = $"Rule-{containerName}-{prefix}",
67+
Enabled = true,
68+
Definition = new BlobLifecycleRuleDefinition
69+
{
70+
Filters = new BlobLifecycleRuleFilter
71+
{
72+
PrefixMatch = new List<string> { $"{containerName}/{prefix}" }
73+
},
74+
Actions = new BlobLifecycleRuleActions
75+
{
76+
BaseBlob = new BlobLifecycleRuleActionBase
77+
{
78+
Delete = new BlobLifecycleRuleActionDelete
79+
{
80+
DaysAfterModificationGreaterThan = groupConfig.Lifecycle.DaysBeforeExpiry.Value
81+
}
82+
}
83+
}
84+
}
85+
};
86+
87+
rules.Add(rule);
88+
}
89+
}
90+
91+
lifecycleManagementPolicy.Rules = rules;
92+
93+
try
94+
{
95+
await client.SetBlobLifecyclePolicyAsync(lifecycleManagementPolicy);
96+
logger.LogInformation("Updated lifecycle rules for storage account");
97+
}
98+
catch (Exception e)
99+
{
100+
logger.LogError(e, $"Error updating lifecycle rules for storage account: {e.Message}");
101+
}
102+
}
103+
104+
internal async Task<TestFilesResult> CreateAndReadTestFilesAsync(bool forceAll)
105+
{
106+
// Implementation similar to S3LifecycleUpdater's CreateAndReadTestFilesAsync
107+
// Use BlobContainerClient to perform operations on blobs
108+
}
109+
110+
private async Task<CodeResult> TryAzureOperationAsync(string containerName, string blobName, string operationName,
111+
Func<Task> operation)
112+
{
113+
try
114+
{
115+
await operation();
116+
return CodeResult.Ok();
117+
}
118+
catch (Azure.RequestFailedException e)
119+
{
120+
var err = CodeResult.FromException(e, $"Azure {operationName} {containerName} {blobName}");
121+
logger.LogAsError(err);
122+
return err;
123+
}
124+
}
125+
126+
internal record class TestFilesResult(List<CodeResult> Results, bool ReadsFailed, bool WritesFailed, bool ListFailed, bool DeleteFailed);
127+
}
128+
}

0 commit comments

Comments
 (0)