-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Stub AzureBlob health+lifecycle rule updater
- Loading branch information
Showing
2 changed files
with
170 additions
and
0 deletions.
There are no files selected for viewing
42 changes: 42 additions & 0 deletions
42
src/Imageflow.Server.Storage.AzureBlob/Caching/HealthCheck.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using Azure.Storage.Blobs; | ||
using Imazen.Abstractions.BlobCache; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Imageflow.Server.Storage.AzureBlob.Caching; | ||
|
||
internal record HealthCheck(IBlobCache Cache, NamedCacheConfiguration Config, ILogger Logger, Dictionary<BlobGroup, BlobServiceClient> ServiceClients, | ||
ContainerExistenceCache ContainerExists) | ||
{ | ||
|
||
// this.InitialCacheCapabilities = new BlobCacheCapabilities | ||
// { | ||
// CanFetchMetadata = true, | ||
// CanFetchData = true, | ||
// CanConditionalFetch = false, | ||
// CanPut = true, | ||
// CanConditionalPut = false, | ||
// CanDelete = false, | ||
// CanSearchByTag = false, | ||
// CanPurgeByTag = false, | ||
// CanReceiveEvents = false, | ||
// SupportsHealthCheck = false, | ||
// SubscribesToRecentRequest = false, | ||
// SubscribesToExternalHits = true, | ||
// SubscribesToFreshResults = true, | ||
// RequiresInlineExecution = false, | ||
// FixedSize = false | ||
// }; | ||
// | ||
|
||
public ValueTask<IBlobCacheHealthDetails> CacheHealthCheck(CancellationToken cancellationToken = default) | ||
{ | ||
|
||
} | ||
|
||
internal record BasicHealthDetails(bool CanFetchData, bool CanFetchMetadata, bool CanConditionalFetch, bool CanPut, bool CanConditionalPut, bool CanSearchByTag, bool CanPurgeByTag); | ||
|
||
internal ValueTask<BasicHealthDetails> CheckGroup(BlobGroup group, CancellationToken cancellationToken = default) | ||
{ | ||
|
||
} | ||
} |
128 changes: 128 additions & 0 deletions
128
src/Imageflow.Server.Storage.AzureBlob/Caching/LifecycleRuleUpdater.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
using Azure.Storage.Blobs; | ||
using Azure.Storage.Blobs.Models; | ||
using Imazen.Common.Concurrency; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Imazen.Abstractions.Logging; | ||
using Imazen.Abstractions.Resulting; | ||
|
||
namespace Imageflow.Server.Storage.AzureBlob.Caching | ||
{ | ||
internal class LifecycleRuleUpdater | ||
{ | ||
private readonly NamedCacheConfiguration config; | ||
private readonly IReLogger logger; | ||
private readonly BlobServiceClient defaultClient; | ||
private readonly BasicAsyncLock updateLock = new BasicAsyncLock(); | ||
private bool updateComplete = false; | ||
|
||
public LifecycleRuleUpdater(NamedCacheConfiguration config, BlobServiceClient defaultClient, IReLogger logger) | ||
{ | ||
this.config = config; | ||
this.logger = logger.WithSubcategory(nameof(LifecycleRuleUpdater)); | ||
this.defaultClient = defaultClient; | ||
} | ||
|
||
internal async Task UpdateIfIncompleteAsync() | ||
{ | ||
if (updateComplete) return; | ||
|
||
using (await updateLock.LockAsync()) | ||
{ | ||
if (updateComplete) return; | ||
await CreateContainersAsync(); | ||
await UpdateLifecycleRulesAsync(); | ||
await CreateAndReadTestFilesAsync(false); | ||
updateComplete = true; | ||
} | ||
} | ||
|
||
internal async Task CreateContainersAsync() | ||
{ | ||
// Implementation similar to S3LifecycleUpdater's CreateBucketsAsync | ||
// Use BlobServiceClient to create containers if they don't exist | ||
} | ||
|
||
internal async Task UpdateLifecycleRulesAsync() | ||
{ | ||
var client = defaultClient; | ||
var lifecycleManagementPolicy = new BlobLifecycleManagementPolicy(); | ||
var rules = new List<BlobLifecycleRule>(); | ||
|
||
foreach (var groupConfig in config.BlobGroupConfigurations.Values) | ||
{ | ||
if (groupConfig.UpdateLifecycleRules == false) continue; | ||
|
||
var containerName = groupConfig.Location.ContainerName; | ||
var prefix = groupConfig.Location.BlobPrefix; | ||
|
||
if (groupConfig.Lifecycle.DaysBeforeExpiry.HasValue) | ||
{ | ||
var rule = new BlobLifecycleRule | ||
{ | ||
Name = $"Rule-{containerName}-{prefix}", | ||
Enabled = true, | ||
Definition = new BlobLifecycleRuleDefinition | ||
{ | ||
Filters = new BlobLifecycleRuleFilter | ||
{ | ||
PrefixMatch = new List<string> { $"{containerName}/{prefix}" } | ||
}, | ||
Actions = new BlobLifecycleRuleActions | ||
{ | ||
BaseBlob = new BlobLifecycleRuleActionBase | ||
{ | ||
Delete = new BlobLifecycleRuleActionDelete | ||
{ | ||
DaysAfterModificationGreaterThan = groupConfig.Lifecycle.DaysBeforeExpiry.Value | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
|
||
rules.Add(rule); | ||
} | ||
} | ||
|
||
lifecycleManagementPolicy.Rules = rules; | ||
|
||
try | ||
{ | ||
await client.SetBlobLifecyclePolicyAsync(lifecycleManagementPolicy); | ||
logger.LogInformation("Updated lifecycle rules for storage account"); | ||
} | ||
catch (Exception e) | ||
{ | ||
logger.LogError(e, $"Error updating lifecycle rules for storage account: {e.Message}"); | ||
} | ||
} | ||
|
||
internal async Task<TestFilesResult> CreateAndReadTestFilesAsync(bool forceAll) | ||
{ | ||
// Implementation similar to S3LifecycleUpdater's CreateAndReadTestFilesAsync | ||
// Use BlobContainerClient to perform operations on blobs | ||
} | ||
|
||
private async Task<CodeResult> TryAzureOperationAsync(string containerName, string blobName, string operationName, | ||
Func<Task> operation) | ||
{ | ||
try | ||
{ | ||
await operation(); | ||
return CodeResult.Ok(); | ||
} | ||
catch (Azure.RequestFailedException e) | ||
{ | ||
var err = CodeResult.FromException(e, $"Azure {operationName} {containerName} {blobName}"); | ||
logger.LogAsError(err); | ||
return err; | ||
} | ||
} | ||
|
||
internal record class TestFilesResult(List<CodeResult> Results, bool ReadsFailed, bool WritesFailed, bool ListFailed, bool DeleteFailed); | ||
} | ||
} |