Skip to content

Commit 0236ede

Browse files
authored
Merge pull request #5 from felixclase/develop
Version Alpha..
2 parents 39b9652 + cc678f0 commit 0236ede

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3022
-81
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,4 @@ ASALocalRun/
328328

329329
# MFractors (Xamarin productivity tool) working folder
330330
.mfractor/
331+
*.db

README.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
[![License MIT](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT)
66

77
## Overview
8-
SQLite storage for Hangfire
8+
9+
An Alternative SQLite Storage for Hangfire.
10+
11+
This project was created by abandonment **Hangfire.SQLite** storage (https://github.com/wanlitao/HangfireExtension), as an alternative to use SQLite with Hangfire.
912

1013
## Build Status
1114
`Platform` | `Master` | `Develop`
@@ -15,22 +18,36 @@ SQLite storage for Hangfire
1518

1619
## Installation
1720

18-
## Usage
21+
Install a package from Nuget.
1922

20-
### DotNetCore
23+
```
24+
Install-Package Hangfire.Storage.SQLite
25+
```
2126

22-
### NetFramework
27+
## Usage
28+
29+
This is how you connect to an SQLite instance
30+
```csharp
31+
GlobalConfiguration.Configuration.UseSQLiteStorage();
32+
```
2333

2434
### Example
2535

26-
#### Options
36+
```csharp
37+
services.AddHangfire(configuration => configuration
38+
.UseSimpleAssemblyNameTypeSerializer()
39+
.UseRecommendedSerializerSettings()
40+
.UseSQLiteStorage());
41+
```
2742

2843
## Thanks
2944

45+
This project is mainly based on **Hangfire.LiteDB** storage by [@codeyu](https://github.com/codeyu) (https://github.com/codeyu/Hangfire.LiteDB)
46+
3047
## Donation
3148
If this project help you reduce time to develop, you can give me a cup of coffee :)
3249

3350
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=RMLQM296TCM38&item_name=For+the+development+of+Hangfire.Storage.SQLite&currency_code=USD&source=url)
3451

3552
## License
36-
This project is under MIT license. You can obtain the license copy [here](https://github.com/felixclase/Hangfire.Storage.SQLite/blob/develop/LICENSE).
53+
This project is under MIT license. You can obtain the license copy [here](https://github.com/felixclase/Hangfire.Storage.SQLite/blob/develop/LICENSE).
Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,137 @@
1-
using System;
1+
using Hangfire.Annotations;
2+
using Hangfire.Logging;
3+
using Hangfire.Server;
4+
using System;
25
using System.Collections.Generic;
6+
using System.Linq;
37
using System.Text;
8+
using System.Threading;
9+
using Hangfire.Storage.SQLite.Entities;
410

511
namespace Hangfire.Storage.SQLite
612
{
7-
public class CountersAggregator
13+
/// <summary>
14+
/// Represents Counter collection aggregator for SQLite database
15+
/// </summary>
16+
#pragma warning disable CS0618
17+
public class CountersAggregator : IBackgroundProcess, IServerComponent
18+
#pragma warning restore CS0618
819
{
20+
private static readonly ILog Logger = LogProvider.For<CountersAggregator>();
21+
private const int NumberOfRecordsInSinglePass = 1000;
22+
23+
private static readonly TimeSpan DelayBetweenPasses = TimeSpan.FromMilliseconds(500);
24+
25+
private readonly SQLiteStorage _storage;
26+
private readonly TimeSpan _interval;
27+
28+
/// <summary>
29+
/// Constructs Counter collection aggregator
30+
/// </summary>
31+
/// <param name="storage">SQLite storage</param>
32+
/// <param name="interval">Checking interval</param>
33+
public CountersAggregator(SQLiteStorage storage, TimeSpan interval)
34+
{
35+
_storage = storage ?? throw new ArgumentNullException(nameof(storage));
36+
_interval = interval;
37+
}
38+
39+
/// <summary>
40+
/// Runs aggregator
41+
/// </summary>
42+
/// <param name="context">Background processing context</param>
43+
public void Execute([NotNull] BackgroundProcessContext context)
44+
{
45+
Execute(context.StoppingToken);
46+
}
47+
48+
/// <summary>
49+
/// Runs aggregator
50+
/// </summary>
51+
/// <param name="cancellationToken">Cancellation token</param>
52+
public void Execute(CancellationToken cancellationToken)
53+
{
54+
Logger.DebugFormat("Aggregating records in 'Counter' table...");
55+
56+
long removedCount = 0;
57+
58+
do
59+
{
60+
using (var storageConnection = (HangfireSQLiteConnection)_storage.GetConnection())
61+
{
62+
var storageDb = storageConnection.DbContext;
63+
64+
var recordsToAggregate = storageDb
65+
.CounterRepository
66+
.Take(NumberOfRecordsInSinglePass)
67+
.ToList();
68+
69+
var recordsToMerge = recordsToAggregate
70+
.GroupBy(_ => _.Key).Select(_ => new
71+
{
72+
_.Key,
73+
Value = _.Sum(x => x.Value),
74+
ExpireAt = _.Max(x => x.ExpireAt)
75+
});
76+
77+
foreach (var id in recordsToAggregate.Select(_ => _.Id))
78+
{
79+
storageDb
80+
.CounterRepository
81+
.Delete(_ => _.Id == id);
82+
removedCount++;
83+
}
84+
85+
foreach (var item in recordsToMerge)
86+
{
87+
AggregatedCounter aggregatedItem = storageDb
88+
.AggregatedCounterRepository
89+
.FirstOrDefault(_ => _.Key == item.Key);
90+
91+
if (aggregatedItem != null)
92+
{
93+
var aggregatedCounters = storageDb.AggregatedCounterRepository.Where(_ => _.Key == item.Key).ToList();
94+
95+
foreach (var counter in aggregatedCounters)
96+
{
97+
counter.Value = counter.Value + item.Value;
98+
counter.ExpireAt = item.ExpireAt > aggregatedItem.ExpireAt
99+
? (item.ExpireAt > DateTime.MinValue ? item.ExpireAt : DateTime.MinValue)
100+
: (aggregatedItem.ExpireAt > DateTime.MinValue ?
101+
aggregatedItem.ExpireAt : DateTime.MinValue);
102+
storageDb.Database.Update(counter);
103+
}
104+
}
105+
else
106+
{
107+
storageDb
108+
.Database
109+
.Insert(new AggregatedCounter
110+
{
111+
Key = item.Key,
112+
Value = item.Value,
113+
ExpireAt = item.ExpireAt
114+
});
115+
}
116+
}
117+
}
118+
119+
if (removedCount >= NumberOfRecordsInSinglePass)
120+
{
121+
cancellationToken.WaitHandle.WaitOne(DelayBetweenPasses);
122+
cancellationToken.ThrowIfCancellationRequested();
123+
}
124+
} while (removedCount >= NumberOfRecordsInSinglePass);
125+
126+
cancellationToken.WaitHandle.WaitOne(_interval);
127+
}
128+
129+
/// <summary>
130+
/// Returns text representation of the object
131+
/// </summary>
132+
public override string ToString()
133+
{
134+
return "SQLite Counter Collection Aggregator";
135+
}
9136
}
10137
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Hangfire.Storage.SQLite
6+
{
7+
/// <summary>
8+
///
9+
/// </summary>
10+
public class EnqueuedAndFetchedCountDto
11+
{
12+
/// <summary>
13+
///
14+
/// </summary>
15+
public int? EnqueuedCount { get; set; }
16+
/// <summary>
17+
///
18+
/// </summary>
19+
public int? FetchedCount { get; set; }
20+
}
21+
}

src/main/Hangfire.Storage.SQLite/Entities/AggregatedCounter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55

66
namespace Hangfire.Storage.SQLite.Entities
77
{
8-
internal class AggregatedCounter
8+
public class AggregatedCounter
99
{
1010
[PrimaryKey]
1111
[MaxLength(DefaultValues.MaxLengthKeyColumn)]
1212
public string Key { get; set; }
1313

14-
public int Value { get; set; }
14+
public decimal Value { get; set; }
1515

1616
[Indexed(Name = "IX_AggregatedCounter_ExpireAt", Order = 1, Unique = false)]
1717
public DateTime ExpireAt { get; set; }

src/main/Hangfire.Storage.SQLite/Entities/Counter.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55

66
namespace Hangfire.Storage.SQLite.Entities
77
{
8-
internal class Counter
8+
public class Counter
99
{
1010
[PrimaryKey]
11+
[MaxLength(DefaultValues.MaxLengthKeyColumn)]
12+
public string Id { get; set; }
13+
1114
[MaxLength(DefaultValues.MaxLengthKeyColumn)]
1215
public string Key { get; set; }
1316

14-
public int Value { get; set; }
17+
public decimal Value { get; set; }
1518

1619
[Indexed(Name = "IX_Counter_ExpireAt", Order = 1, Unique = false)]
17-
public DateTime? ExpireAt { get; set; }
20+
public DateTime ExpireAt { get; set; }
1821
}
1922
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using SQLite;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace Hangfire.Storage.SQLite.Entities
7+
{
8+
/// <summary>
9+
/// Document used for holding a distributed lock in SQLite.
10+
/// </summary>
11+
public class DistributedLock
12+
{
13+
/// <summary>
14+
/// The unique id of the document.
15+
/// </summary>
16+
[PrimaryKey]
17+
public string Id { get; set; }
18+
19+
/// <summary>
20+
/// The name of the resource being held.
21+
/// </summary>
22+
public string Resource { get; set; }
23+
24+
/// <summary>
25+
/// The timestamp for when the lock expires.
26+
/// This is used if the lock is not maintained or
27+
/// cleaned up by the owner (e.g. process was shut down).
28+
/// </summary>
29+
public DateTime ExpireAt { get; set; }
30+
}
31+
}

src/main/Hangfire.Storage.SQLite/Entities/Job.cs renamed to src/main/Hangfire.Storage.SQLite/Entities/HangfireJob.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
namespace Hangfire.Storage.SQLite.Entities
77
{
8-
internal class Job
8+
[Table("Job")]
9+
public class HangfireJob
910
{
1011
[PrimaryKey, AutoIncrement]
1112
public int Id { get; set; }
@@ -17,14 +18,14 @@ internal class Job
1718
public string StateName { get; set; }
1819

1920
[MaxLength(DefaultValues.MaxLengthVarCharColumn)]
20-
public string InvocationDate { get; set; }
21+
public string InvocationData { get; set; }
2122

2223
[MaxLength(DefaultValues.MaxLengthVarCharColumn)]
2324
public string Arguments { get; set; }
2425

2526
public DateTime CreatedAt { get; set; }
2627

2728
[Indexed(Name = "IX_Job_ExpireAt", Order = 2, Unique = false)]
28-
public DateTime? ExpireAt { get; set; }
29+
public DateTime ExpireAt { get; set; }
2930
}
3031
}

src/main/Hangfire.Storage.SQLite/Entities/HangfireList.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@
66
namespace Hangfire.Storage.SQLite.Entities
77
{
88
[Table("List")]
9-
internal class HangfireList
9+
public class HangfireList
1010
{
11+
private string _listPK = string.Empty;
12+
1113
[PrimaryKey]
12-
public string ListPK { get { return Id + "_" + Key; } }
14+
public string ListPK {
15+
get => Id + "_" + Key;
16+
set => _listPK = value;
17+
}
1318

14-
[AutoIncrement]
19+
//[AutoIncrement]
1520
[Indexed(Name = "IX_List_Id", Order = 1, Unique = false)]
1621
public int Id { get; set; }
1722

@@ -23,6 +28,6 @@ internal class HangfireList
2328
public string Value { get; set; }
2429

2530
[Indexed(Name = "IX_List_ExpireAt", Order = 3, Unique = false)]
26-
public DateTime? ExpireAt { get; set; }
31+
public DateTime ExpireAt { get; set; }
2732
}
2833
}

src/main/Hangfire.Storage.SQLite/Entities/Server.cs renamed to src/main/Hangfire.Storage.SQLite/Entities/HangfireServer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
namespace Hangfire.Storage.SQLite.Entities
77
{
8-
internal class Server
8+
[Table("Server")]
9+
public class HangfireServer
910
{
1011
[PrimaryKey]
1112
[MaxLength(DefaultValues.MaxLengthIdColumn)]

0 commit comments

Comments
 (0)