Consider adding ETCD backend
See https://etcd.io/docs/v3.2/dev-guide/api_concurrency_reference_v3/ Could use https://github.com/shubhamranjan/dotnet-etcd
@madelson i'm quite interested in this feature, as it seems to offer a better lease mechanism than sqlserver's implementation. Can i take this task and where do i start if i can?
@thangnguyen-69 I'd be happy to have you contribute this! As a starting point I would focus on providing an implementation of IDistributedLock.
https://github.com/madelson/DistributedLock/pull/51/files gives a good sense of what adding a new provider looks like.
For the new project, I'd recommend copying over one of the existing csproj files and modifying so you get all the right setup.
One thing to call out is that the file DistributedLock.FileSystem/FileDistributedLock.IDistributedLock.cs is auto-generated by running the DistributedLockCodeGen test project in the solution; you'll want to do the same thing for your impl (this was all created before source generators existed!).
My suggestion would be to take a crack at it and see how far you can get, then create a rough draft PR where we can discuss. I wouldn't worry too much about polish in the first pass as things will likely change; let's aim to get the right structure in place (which is fairly rigid and dictated by the interfaces/codegen/test harness) and then it's easier to work from there.
The most important parts of the implementation will be how we map IDistributedLock's behavioral requirements to etcd's APIs. For example:
- Handling of names: distributedlock lets you pass any name and hashes it as needed to fit the underlying provider's constraints
- Blocking vs. busy waiting semantics
- Cancellation & timeouts We can discuss those in more depth on the PR or here before you dive in.
Happy to help at any point along the way if you have questions.
@madelson i have several question before making a draft pr:
- i imagine etcd will have more similar semantic to AzureBlob and not FileSystem though so i think i will follow that route instead.
- the latest dotnet-etcd (8.0.1) only support net8.0 and net9.0, so can i make this implementation target only > net8.0 or it must be general implementation that target net462;netstandard2.0;netstandard2.1 like the other projects?
i imagine etcd will have more similar semantic to AzureBlob and not FileSystem though so i think i will follow that route instead.
That's fine. I was more trying to just point out a PR that shows the full set of changes related to adding a new provider. If you want to follow the Azure one that should work too.
the latest dotnet-etcd (8.0.1) only support net8.0 and net9.0, so can i make this implementation target only > net8.0 or it must be general implementation that target net462;netstandard2.0;netstandard2.1 like the other projects?
In that case let's just target net8.0. You'll need the reference from the main DistributedLock project to be conditional based on target framework.
The one annoying thing to deal with is that the test project's codegen stuff will generate CombinatorialTests.cs which does not support #if forks. I do want any new provider to support the combinatorial tests through the main flow. What I would recommend is that we have the testing abstractions for etcd be available in all frameworks, but branch the implementation on framework and have it just Assert.Pass() in the not supported case. For example:
[SupportsContinuousIntegration]
public sealed class TestingEtcdDistributedLockProvider : TestingLockProvider<TestingEtcdSynchronizationStrategy>
{
public override IDistributedLock CreateLockWithExactName(string name)
{
#if NET8_0_OR_GREATER
return new EtcdDistributedLock(name);
#else
Assert.Pass();
throw new NotSupportedException();
#endif
}
public override string GetSafeName(string name) =>
#if NET8_0_OR_GREATER
new EtcdDistributedLock(name).Name;
#else
name;
#endif
}
Here's the draft PR https://github.com/madelson/DistributedLock/pull/247 Most design come from Azure Blob storage code, but the Client does not have that many level (BlobClient,BlobLeaseClient,BlobContainerClient,...) as EtcdClient.
Also i'm not sure what you mean by Blocking vs. busy waiting semantics because in the code so far (at least the EtcdLeaseDistributedLock.TryAcquireAsync) i only saw busy waiting strat, i.e: send request to get the lock --> return error immediately instead of waiting if the lock is not available) and thus the generated tests fail.