From bd13ff7d6c8afd68b060915ac90cbc8974201881 Mon Sep 17 00:00:00 2001 From: Mohammed Ahmed Hussien Date: Mon, 22 Sep 2025 18:33:27 +0300 Subject: [PATCH 1/4] Fix SemaphoreSlim object shouldn't be call from inside method bug --- src/core/SnowflakOptions.cs | 7 +++++++ src/core/SnowflakeIdConfig.cs | 6 ++++++ src/core/SnowflakeIdService.cs | 23 +++++++++++++++-------- tests/SnowflakeIdServiceTest.cs | 20 ++++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/core/SnowflakOptions.cs b/src/core/SnowflakOptions.cs index 06ebf0c..3399e16 100644 --- a/src/core/SnowflakOptions.cs +++ b/src/core/SnowflakOptions.cs @@ -1,5 +1,7 @@ // Read more about the licenses under the root of the project in the LICENSE.txt file. +using System; + namespace SnowflakeId.Core { public class SnowflakOptions @@ -15,5 +17,10 @@ public class SnowflakOptions /// Get or set the value that determined whether using console log or not, the default value is false. /// public bool UseConsoleLog { get; set; } + + /// + /// Get or set the custom epoch, the default value of this property with set to epoch is 1970 Jan 1s ( Unix Time ) if value is null. + /// + public DateTime? CustomEpoch { get; set; } } } diff --git a/src/core/SnowflakeIdConfig.cs b/src/core/SnowflakeIdConfig.cs index 4796938..ad0798e 100644 --- a/src/core/SnowflakeIdConfig.cs +++ b/src/core/SnowflakeIdConfig.cs @@ -36,5 +36,11 @@ internal class SnowflakeIdConfig /// 4095 /// public static readonly int MaxSequenceId = (int)(Math.Pow(2, SequenceBits) - 1); + + + /// + public static readonly DateTime DefaultEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public static readonly int MaxDataCenterId = ((1 << MachineIdBits) - 1); } } diff --git a/src/core/SnowflakeIdService.cs b/src/core/SnowflakeIdService.cs index 9ef900e..f2f0200 100644 --- a/src/core/SnowflakeIdService.cs +++ b/src/core/SnowflakeIdService.cs @@ -13,6 +13,7 @@ public class SnowflakeIdService : ISnowflakeService, IDisposable { // Lock Token private readonly object threadLock = new object(); + private readonly SemaphoreSlim sem = new SemaphoreSlim(1, 1); private long _lastTimestamp = -1L; private long _sequence = 0L; @@ -29,13 +30,19 @@ public class SnowflakeIdService : ISnowflakeService, IDisposable /// /// When generating the Id I use the Epoch that start at 1970 Jan 1s ( Unix Time ) /// - public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + public readonly DateTime UnixEpoch; private bool _disposed; public SnowflakeIdService(IOptions options, ILogger logger) { _snowflakOptions = options.Value; _logger = logger ?? new NullLogger(); + + UnixEpoch = options.Value.CustomEpoch ?? SnowflakeIdConfig.DefaultEpoch; + if (_snowflakOptions.DataCenterId < 0 || _snowflakOptions.DataCenterId > SnowflakeIdConfig.MaxDataCenterId) + { + throw new ArgumentException(string.Format("DataCenterId must be between 0 and {0}", SnowflakeIdConfig.MaxDataCenterId)); + } } /// @@ -51,7 +58,8 @@ public virtual long GenerateSnowflakeId() if (currentTimestamp < _lastTimestamp) { if (_snowflakOptions.UseConsoleLog) - _logger.LogError("error in the server clock, the current timestamp should be bigger than generated one, current timestamp is: {0}, and the last generated timestamp is: {1}", currentTimestamp, _lastTimestamp); + _logger.LogError("error in the server clock, the current timestamp should be bigger than generated one, " + + "current timestamp is: {currentTimestamp}, and the last generated timestamp is: {lastTimestamp}", currentTimestamp, _lastTimestamp); throw new InvalidOperationException("Error_In_The_Server_Clock"); } @@ -85,12 +93,11 @@ public virtual long GenerateSnowflakeId() /// cancellationToken /// A new unique number that has a long type. /// - public virtual Task GenerateSnowflakeIdAsync(CancellationToken cancellationToken = default) + public virtual async Task GenerateSnowflakeIdAsync(CancellationToken cancellationToken = default) { - SemaphoreSlim sem = new SemaphoreSlim(1, 1); try { - sem.Wait(cancellationToken); + await sem.WaitAsync(cancellationToken).ConfigureAwait(false); long currentTimestamp = getTimestamp(); if (currentTimestamp < _lastTimestamp) @@ -120,7 +127,7 @@ public virtual Task GenerateSnowflakeIdAsync(CancellationToken cancellatio long result = (currentTimestamp << _timeStampShift) | ((long)_snowflakOptions.DataCenterId << _machaineIdShift) | (_sequence); if (_snowflakOptions.UseConsoleLog) _logger.LogInformation("the gnerated unique id is {0}", result); - return Task.FromResult(result); + return result; } finally { @@ -194,7 +201,7 @@ public virtual long GetSecondsSinceUnixEpochFromId(long snowflakeId) } // 41 bits of 1s, will shifted left by 22 bits. - long timestampMask = 0x1FFFFFFFFFF; + long timestampMask = 0x1FFFFFFFFFF; long timeStamp = (snowflakeId >> _timeStampShift) & timestampMask; return timeStamp; } @@ -212,7 +219,7 @@ public virtual int GetDataCenterIdBySnowflakeId(long snowflakeId) } // 10 bits mask (0b1111111111) will shifted left by 12 bits. - long dataCenterIdMask = 0x3FF; + long dataCenterIdMask = 0x3FF; long dataCenterId = (snowflakeId >> _machaineIdShift) & dataCenterIdMask; return (int)dataCenterId; diff --git a/tests/SnowflakeIdServiceTest.cs b/tests/SnowflakeIdServiceTest.cs index 34b0ef7..3cf4fe2 100644 --- a/tests/SnowflakeIdServiceTest.cs +++ b/tests/SnowflakeIdServiceTest.cs @@ -65,5 +65,25 @@ public void Can_Find_Data_CenterId_From_Generated_UniqueId() } + [Fact] + public async Task Can_Genertate_UniqueId_Asynchrony_In_The_Same_Millisecond() + { + var services = new ServiceCollection(); + services.AddLogging(); + services.AddSnowflakeUniqueId(s => s.DataCenterId = 1); + + var serviceProvider = services.BuildServiceProvider(); + var snowflakeService = serviceProvider.GetRequiredService(); + + var cts = new CancellationTokenSource(); + var tasks = new List>(500_000); + for (int i = 0; i < 50_000; i++) + tasks.Add(Task.Run(() => snowflakeService.GenerateSnowflakeIdAsync(cts.Token))); + + var uniqueIds = await Task.WhenAll(tasks); + var listUniqeness = uniqueIds.Length != uniqueIds.Distinct().Count(); + Assert.False(listUniqeness); + } + } } From b7252877d5169d310094d69f3ab2c91e04cc670a Mon Sep 17 00:00:00 2001 From: Mohammed Ahmed Hussien Date: Thu, 25 Sep 2025 21:36:19 +0300 Subject: [PATCH 2/4] Enhance the generated id methods and option --- example/SnowflakeId.Example/Program.cs | 10 ++++++---- .../SnowflakeIdServiceExtensions.cs | 13 +++++++------ src/core/SnowflakOptions.cs | 2 +- src/core/SnowflakeIdConfig.cs | 7 +------ src/core/SnowflakeIdService.cs | 18 +++++++++++------- tests/SnowflakeIdConfigTest.cs | 6 +----- tests/SnowflakeIdServiceExtensionsTest.cs | 15 +++++++++++---- tests/SnowflakeIdServiceTest.cs | 19 ++++++++++++++++++- 8 files changed, 56 insertions(+), 34 deletions(-) diff --git a/example/SnowflakeId.Example/Program.cs b/example/SnowflakeId.Example/Program.cs index 3e237e7..a545535 100644 --- a/example/SnowflakeId.Example/Program.cs +++ b/example/SnowflakeId.Example/Program.cs @@ -15,10 +15,12 @@ Build and implemented with love by Mohammed Ahmed Hussien Babiker IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices((_, services) => { - services.AddSnowflakeUniqueId(options => - { - options.DataCenterId = 7; - }); + services.AddSnowflakeUniqueId( + // options => + //{ + // options.DataCenterId = 7; + //} + ); }).Build(); var idServive = host.Services.GetRequiredService(); diff --git a/src/core/DependencyInjection/SnowflakeIdServiceExtensions.cs b/src/core/DependencyInjection/SnowflakeIdServiceExtensions.cs index d91db16..22f6863 100644 --- a/src/core/DependencyInjection/SnowflakeIdServiceExtensions.cs +++ b/src/core/DependencyInjection/SnowflakeIdServiceExtensions.cs @@ -10,20 +10,21 @@ namespace SnowflakeId.DependencyInjection public static class SnowflakeIdServiceExtensions { public static IServiceCollection AddSnowflakeUniqueId(this IServiceCollection services, - Action setupAction) + Action setupAction = null) { if (services == null) { throw new ArgumentNullException(nameof(services)); } - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } + services.AddOptions(); + var o = new SnowflakOptions(); + services.AddSingleton(o); + setupAction?.Invoke(o); services.TryAddScoped(); - services.Configure(setupAction); + if (setupAction != null) + services.Configure(setupAction); return services; } } diff --git a/src/core/SnowflakOptions.cs b/src/core/SnowflakOptions.cs index 3399e16..479c578 100644 --- a/src/core/SnowflakOptions.cs +++ b/src/core/SnowflakOptions.cs @@ -11,7 +11,7 @@ public class SnowflakOptions /// or any other unique things in your webfarm /// Be sure to set this property with number greater than zero. /// - public int DataCenterId { get; set; } + public int? DataCenterId { get; set; } /// /// Get or set the value that determined whether using console log or not, the default value is false. diff --git a/src/core/SnowflakeIdConfig.cs b/src/core/SnowflakeIdConfig.cs index ad0798e..1c0cb72 100644 --- a/src/core/SnowflakeIdConfig.cs +++ b/src/core/SnowflakeIdConfig.cs @@ -29,6 +29,7 @@ internal class SnowflakeIdConfig /// /// 1023 + /// ((1 << MachineIdBits) - 1); /// public static readonly int MaxMachineId = (int)(Math.Pow(2, MachineIdBits) - 1); @@ -36,11 +37,5 @@ internal class SnowflakeIdConfig /// 4095 /// public static readonly int MaxSequenceId = (int)(Math.Pow(2, SequenceBits) - 1); - - - /// - public static readonly DateTime DefaultEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - public static readonly int MaxDataCenterId = ((1 << MachineIdBits) - 1); } } diff --git a/src/core/SnowflakeIdService.cs b/src/core/SnowflakeIdService.cs index f2f0200..7b47809 100644 --- a/src/core/SnowflakeIdService.cs +++ b/src/core/SnowflakeIdService.cs @@ -26,6 +26,8 @@ public class SnowflakeIdService : ISnowflakeService, IDisposable private readonly SnowflakOptions _snowflakOptions; private readonly ILogger _logger; + protected readonly int DataCenterId = 1; + private static readonly DateTime DefaultEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// /// When generating the Id I use the Epoch that start at 1970 Jan 1s ( Unix Time ) @@ -38,10 +40,11 @@ public SnowflakeIdService(IOptions options, ILogger(); - UnixEpoch = options.Value.CustomEpoch ?? SnowflakeIdConfig.DefaultEpoch; - if (_snowflakOptions.DataCenterId < 0 || _snowflakOptions.DataCenterId > SnowflakeIdConfig.MaxDataCenterId) + UnixEpoch = options.Value.CustomEpoch ?? DefaultEpoch; + _snowflakOptions.DataCenterId ??= DataCenterId; + if (_snowflakOptions.DataCenterId < 0 || _snowflakOptions.DataCenterId > SnowflakeIdConfig.MaxMachineId) { - throw new ArgumentException(string.Format("DataCenterId must be between 0 and {0}", SnowflakeIdConfig.MaxDataCenterId)); + throw new ArgumentException(string.Format("DataCenterId must be between 0 and {0}", SnowflakeIdConfig.MaxMachineId)); } } @@ -59,7 +62,7 @@ public virtual long GenerateSnowflakeId() { if (_snowflakOptions.UseConsoleLog) _logger.LogError("error in the server clock, the current timestamp should be bigger than generated one, " + - "current timestamp is: {currentTimestamp}, and the last generated timestamp is: {lastTimestamp}", currentTimestamp, _lastTimestamp); + "current timestamp is: {CurrentTimestamp}, and the last generated timestamp is: {LastTimestamp}", currentTimestamp, _lastTimestamp); throw new InvalidOperationException("Error_In_The_Server_Clock"); } @@ -82,7 +85,7 @@ public virtual long GenerateSnowflakeId() long result = (currentTimestamp << _timeStampShift) | ((long)_snowflakOptions.DataCenterId << _machaineIdShift) | (_sequence); if (_snowflakOptions.UseConsoleLog) - _logger.LogInformation("the gnerated unique id is {0}", result); + _logger.LogInformation("the gnerated unique id is {UniqueId}", result); return result; } } @@ -103,7 +106,8 @@ public virtual async Task GenerateSnowflakeIdAsync(CancellationToken cance if (currentTimestamp < _lastTimestamp) { if (_snowflakOptions.UseConsoleLog) - _logger.LogError("error in the server clock, the current timestamp should be bigger than generated one, current timestamp is: {0}, and the last generated timestamp is: {1}", currentTimestamp, _lastTimestamp); + _logger.LogError("error in the server clock, the current timestamp should be bigger than generated one, current timestamp is: {CurrentTimestamp}, " + + "and the last generated timestamp is: {LastTimestamp}", currentTimestamp, _lastTimestamp); throw new InvalidOperationException("Error_In_The_Server_Clock"); } @@ -126,7 +130,7 @@ public virtual async Task GenerateSnowflakeIdAsync(CancellationToken cance long result = (currentTimestamp << _timeStampShift) | ((long)_snowflakOptions.DataCenterId << _machaineIdShift) | (_sequence); if (_snowflakOptions.UseConsoleLog) - _logger.LogInformation("the gnerated unique id is {0}", result); + _logger.LogInformation("the gnerated unique id is {UniqueId}", result); return result; } finally diff --git a/tests/SnowflakeIdConfigTest.cs b/tests/SnowflakeIdConfigTest.cs index fa3ba45..0e7a175 100644 --- a/tests/SnowflakeIdConfigTest.cs +++ b/tests/SnowflakeIdConfigTest.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SnowflakeId.Core; +using SnowflakeId.Core; namespace SnowflakeId.Tests { diff --git a/tests/SnowflakeIdServiceExtensionsTest.cs b/tests/SnowflakeIdServiceExtensionsTest.cs index e74a037..2d0f21f 100644 --- a/tests/SnowflakeIdServiceExtensionsTest.cs +++ b/tests/SnowflakeIdServiceExtensionsTest.cs @@ -17,13 +17,21 @@ namespace SnowflakeId.Tests public class SnowflakeIdServiceExtensionsTest { [Fact] - - public void AddSnowflakeUniqueId_ThrowArgumentNullException_With_Null_SnowflakOptions() + public void Can_Add_SnowflakId_To_Service_Collection_Without_SnowflakeId_Option() { var services = new ServiceCollection(); services.AddLogging(); + services.AddSnowflakeUniqueId(); + + var serviceProvider = services.BuildServiceProvider(); + + var snowflakeId = services.FirstOrDefault(desc => desc.ServiceType == typeof(ISnowflakeService)); + var snowflakeIdOptionGetter = serviceProvider.GetRequiredService>(); + var snowflakeIdOption = snowflakeIdOptionGetter.Value; - Assert.Throws(() => services.AddSnowflakeUniqueId(null)); + Assert.NotNull(snowflakeId); + Assert.Equal(ServiceLifetime.Scoped, snowflakeId.Lifetime); + Assert.Null(snowflakeIdOption.DataCenterId); } [Fact] @@ -57,7 +65,6 @@ public void Can_Replace_SnowflakeId_Default_Registration_By_Creating_Object_That Assert.NotNull(snowflakeId); Assert.Equal(ServiceLifetime.Scoped, snowflakeId.Lifetime); - // Assert.IsType(serviceProvider.GetRequiredService()); } [Fact] diff --git a/tests/SnowflakeIdServiceTest.cs b/tests/SnowflakeIdServiceTest.cs index 3cf4fe2..446f00a 100644 --- a/tests/SnowflakeIdServiceTest.cs +++ b/tests/SnowflakeIdServiceTest.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using SnowflakeId.Core; using SnowflakeId.DependencyInjection; -using System.Collections.Generic; namespace SnowflakeId.Tests { @@ -85,5 +84,23 @@ public async Task Can_Genertate_UniqueId_Asynchrony_In_The_Same_Millisecond() Assert.False(listUniqeness); } + + [Fact] + public void DataCenterId_Is_Equal_To_One_When_Registering_SnowflakeId_WithoutOptions() + { + var services = new ServiceCollection(); + services.AddLogging(); + services.AddSnowflakeUniqueId(); + + var serviceProvider = services.BuildServiceProvider(); + var snowflakeService = serviceProvider.GetRequiredService(); + + var id = snowflakeService.GenerateSnowflakeId(); + var dataCenterId = snowflakeService.GetDataCenterIdBySnowflakeId(id); + Assert.IsType(dataCenterId); + Assert.Equal(1, dataCenterId); + } + + } } From c8c5a23d97a80d4c34cc5da0a4da606265240ae2 Mon Sep 17 00:00:00 2001 From: Mohammed Ahmed Hussien Date: Thu, 25 Sep 2025 22:19:40 +0300 Subject: [PATCH 3/4] Adding snowflake Id events before and after id creation process --- example/SnowflakeId.Example/Program.cs | 24 ++++++++--- src/core/Events/SnowflakeIdCreatedContext.cs | 28 +++++++++++++ src/core/Events/SnowflakeIdCreatingContext.cs | 18 ++++++++ src/core/Events/SnowflakeIdEvents.cs | 42 +++++++++++++++++++ src/core/SnowflakOptions.cs | 6 +++ src/core/SnowflakeId.Core.csproj | 2 +- src/core/SnowflakeIdService.cs | 38 +++++++++++++++++ 7 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 src/core/Events/SnowflakeIdCreatedContext.cs create mode 100644 src/core/Events/SnowflakeIdCreatingContext.cs create mode 100644 src/core/Events/SnowflakeIdEvents.cs diff --git a/example/SnowflakeId.Example/Program.cs b/example/SnowflakeId.Example/Program.cs index a545535..ec6db2c 100644 --- a/example/SnowflakeId.Example/Program.cs +++ b/example/SnowflakeId.Example/Program.cs @@ -8,18 +8,32 @@ Build and implemented with love by Mohammed Ahmed Hussien Babiker using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using SnowflakeId.Core; +using SnowflakeId.Core.Events; using SnowflakeId.DependencyInjection; using System; +using System.Threading.Tasks; IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices((_, services) => { - services.AddSnowflakeUniqueId( - // options => - //{ - // options.DataCenterId = 7; - //} + services.AddSnowflakeUniqueId( options => + { + options.DataCenterId = 7; + options.Events = new SnowflakeIdEvents + { + OnCreatedSnowflakeId = context => + { + Console.WriteLine("OnCreatedSnowflakeId --> The Id is: {0} and is generated At: {1}", context.Id, context.GeneratedDateTime); + return Task.CompletedTask; + }, + OnCreatingSnowflakeId = context => + { + Console.WriteLine("OnCreatingSnowflakeId --> Generating Id at data center has id: {0}", context.DataCenterId); + return Task.CompletedTask; + } + }; + } ); }).Build(); diff --git a/src/core/Events/SnowflakeIdCreatedContext.cs b/src/core/Events/SnowflakeIdCreatedContext.cs new file mode 100644 index 0000000..f394023 --- /dev/null +++ b/src/core/Events/SnowflakeIdCreatedContext.cs @@ -0,0 +1,28 @@ +// Read more about the licenses under the root of the project in the LICENSE.txt file. + +using System; +namespace SnowflakeId.Core.Events; + +public class SnowflakeIdCreatedContext +{ + /// + /// Get ot set snowflakeId. + /// + public long Id { get; set; } + + /// + /// Get or set the generation datetime of the snowflakeId. + /// + public DateTime GeneratedDateTime { get; set; } + + /// + /// Gets or sets the identifier of the data center. + /// + public int DataCenterId { get; set; } + + /// + /// Gets or sets the default epoch (1970 Jan 1st - Unix Time). + /// Default value is 1970 Jan 1st if the is null."/> + /// + public DateTime DefaultEpoch { get; set; } +} diff --git a/src/core/Events/SnowflakeIdCreatingContext.cs b/src/core/Events/SnowflakeIdCreatingContext.cs new file mode 100644 index 0000000..17728ab --- /dev/null +++ b/src/core/Events/SnowflakeIdCreatingContext.cs @@ -0,0 +1,18 @@ +// Read more about the licenses under the root of the project in the LICENSE.txt file. + +using System; +namespace SnowflakeId.Core.Events; + +public class SnowflakeIdCreatingContext +{ + /// + /// Gets or sets the default epoch (1970 Jan 1st - Unix Time). + /// Default value is 1970 Jan 1st if the is null."/> + /// + public DateTime DefaultEpoch { get; set; } + + /// + /// Gets or sets the identifier of the data center. + /// + public int DataCenterId { get; set; } +} diff --git a/src/core/Events/SnowflakeIdEvents.cs b/src/core/Events/SnowflakeIdEvents.cs new file mode 100644 index 0000000..4d31235 --- /dev/null +++ b/src/core/Events/SnowflakeIdEvents.cs @@ -0,0 +1,42 @@ +// Read more about the licenses under the root of the project in the LICENSE.txt file. + +using System; +using System.Threading.Tasks; +namespace SnowflakeId.Core.Events; + +public class SnowflakeIdEvents +{ + /// + /// Invoke before creating a snowflakeId. + /// + public Func OnCreatingSnowflakeId { get; set; } = context => Task.CompletedTask; + + /// + /// Invoke after a snowflakeId has been created. + /// + public Func OnCreatedSnowflakeId { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked before creating a snowflakeId. + /// + public virtual Task CreatingSnowflakeId(SnowflakeIdCreatingContext context) + { + if (OnCreatingSnowflakeId != null) + { + return OnCreatingSnowflakeId.Invoke(context); + } + return Task.CompletedTask; + } + + /// + /// Invoked after a snowflakeId has been created. + /// + public virtual Task CreatedSnowflakeId(SnowflakeIdCreatedContext context) + { + if (OnCreatedSnowflakeId != null) + { + return OnCreatedSnowflakeId.Invoke(context); + } + return Task.CompletedTask; + } +} diff --git a/src/core/SnowflakOptions.cs b/src/core/SnowflakOptions.cs index 479c578..f031d7a 100644 --- a/src/core/SnowflakOptions.cs +++ b/src/core/SnowflakOptions.cs @@ -1,5 +1,6 @@ // Read more about the licenses under the root of the project in the LICENSE.txt file. +using SnowflakeId.Core.Events; using System; namespace SnowflakeId.Core @@ -22,5 +23,10 @@ public class SnowflakOptions /// Get or set the custom epoch, the default value of this property with set to epoch is 1970 Jan 1s ( Unix Time ) if value is null. /// public DateTime? CustomEpoch { get; set; } + + /// + /// events + public SnowflakeIdEvents Events { get; set; } = new SnowflakeIdEvents(); + } } diff --git a/src/core/SnowflakeId.Core.csproj b/src/core/SnowflakeId.Core.csproj index b4c66c8..9ac69e6 100644 --- a/src/core/SnowflakeId.Core.csproj +++ b/src/core/SnowflakeId.Core.csproj @@ -42,7 +42,7 @@ - + \ No newline at end of file diff --git a/src/core/SnowflakeIdService.cs b/src/core/SnowflakeIdService.cs index 7b47809..688d489 100644 --- a/src/core/SnowflakeIdService.cs +++ b/src/core/SnowflakeIdService.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; +using SnowflakeId.Core.Events; using System; using System.Threading; using System.Threading.Tasks; @@ -29,6 +30,7 @@ public class SnowflakeIdService : ISnowflakeService, IDisposable protected readonly int DataCenterId = 1; private static readonly DateTime DefaultEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + /// /// When generating the Id I use the Epoch that start at 1970 Jan 1s ( Unix Time ) /// @@ -56,6 +58,13 @@ public virtual long GenerateSnowflakeId() { lock (threadLock) { + var idCreatingContext = new SnowflakeIdCreatingContext + { + DataCenterId = _snowflakOptions.DataCenterId.Value, + DefaultEpoch = UnixEpoch + }; + _snowflakOptions.Events.CreatingSnowflakeId(idCreatingContext).GetAwaiter().GetResult(); + long currentTimestamp = getTimestamp(); if (currentTimestamp < _lastTimestamp) @@ -86,6 +95,17 @@ public virtual long GenerateSnowflakeId() long result = (currentTimestamp << _timeStampShift) | ((long)_snowflakOptions.DataCenterId << _machaineIdShift) | (_sequence); if (_snowflakOptions.UseConsoleLog) _logger.LogInformation("the gnerated unique id is {UniqueId}", result); + + var idCreatedContext = new SnowflakeIdCreatedContext + { + Id = result, + GeneratedDateTime = GetDateTimeBySecondsSinceUnixEpoch(GetSecondsSinceUnixEpochFromId(result)), + DataCenterId = _snowflakOptions.DataCenterId.Value, + DefaultEpoch = UnixEpoch + }; + _snowflakOptions.Events.CreatedSnowflakeId(idCreatedContext).GetAwaiter().GetResult(); + + return result; } } @@ -101,6 +121,13 @@ public virtual async Task GenerateSnowflakeIdAsync(CancellationToken cance try { await sem.WaitAsync(cancellationToken).ConfigureAwait(false); + var idCreatingContext = new SnowflakeIdCreatingContext + { + DataCenterId = _snowflakOptions.DataCenterId.Value, + DefaultEpoch = UnixEpoch + }; + await _snowflakOptions.Events.CreatingSnowflakeId(idCreatingContext).ConfigureAwait(false); + long currentTimestamp = getTimestamp(); if (currentTimestamp < _lastTimestamp) @@ -131,6 +158,17 @@ public virtual async Task GenerateSnowflakeIdAsync(CancellationToken cance long result = (currentTimestamp << _timeStampShift) | ((long)_snowflakOptions.DataCenterId << _machaineIdShift) | (_sequence); if (_snowflakOptions.UseConsoleLog) _logger.LogInformation("the gnerated unique id is {UniqueId}", result); + + var idCreatedContext = new SnowflakeIdCreatedContext + { + Id = result, + GeneratedDateTime = GetDateTimeBySecondsSinceUnixEpoch(GetSecondsSinceUnixEpochFromId(result)), + DataCenterId = _snowflakOptions.DataCenterId.Value, + DefaultEpoch = UnixEpoch + + }; + await _snowflakOptions.Events.CreatedSnowflakeId(idCreatedContext).ConfigureAwait(false); + return result; } finally From 85af19bf3bebb6b17371a3cd294a5069b8715fb9 Mon Sep 17 00:00:00 2001 From: Mohammed Ahmed Hussien Date: Fri, 10 Oct 2025 10:33:51 +0300 Subject: [PATCH 4/4] Updated and publishing the package to Nuget (Version 3.2.0) --- src/core/SnowflakeId.Core.csproj | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/SnowflakeId.Core.csproj b/src/core/SnowflakeId.Core.csproj index 9ac69e6..8d477d2 100644 --- a/src/core/SnowflakeId.Core.csproj +++ b/src/core/SnowflakeId.Core.csproj @@ -8,16 +8,13 @@ Mohammed Ahmed Hussien https://github.com/Shoogn/SnowflakeId https://github.com/Shoogn/SnowflakeId - 3.0.1 + 3.2.0 git - SnowflakeId, UniqueSnowflakeId, UniqueId + SnowflakeId, UniqueSnowflakeId, UniqueId, Primary Keys en-SD - This package implements the twitter's snowflakeId algorithm, - the source code is written in C# programming language, - and the main benefits of this library is to help anyone - wroks with Distrbuted Systems to generate a unique Ids for these Systems or - for Primary Keys is the RDMS such as SQL Server, Oracle, MySQL; or for any other situation that reuired unique Ids. + This is an implementation of snowflakeId algorithm in C# programming language, this algorithm is developed by X formally (Twitter), the source code is written in C# programming language, + and the main benefits of this library is to help anyone wroks with Distrbuted Systems to generate a unique Ids for these Systems or for Primary Keys is the [RDMS] such as SQL Server, Oracle, MySQL; or for any other situation that required unique Ids.