Skip to content

Commit 9f4785d

Browse files
committed
HttpApiFactory自动退出cleanup循环
1 parent 22fcc61 commit 9f4785d

File tree

6 files changed

+97
-130
lines changed

6 files changed

+97
-130
lines changed

WebApiClient/HttpApiFactory.cs

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -35,37 +35,30 @@ public class HttpApiFactory<TInterface> : IHttpApiFactory<TInterface>, IHttpApiF
3535
private TimeSpan cleanupInterval = TimeSpan.FromSeconds(10d);
3636

3737
/// <summary>
38-
/// 过期的记录
38+
/// 过期的拦截器
3939
/// </summary>
40-
private readonly ConcurrentQueue<ExpiredEntry> expiredEntries = new ConcurrentQueue<ExpiredEntry>();
40+
private readonly ConcurrentQueue<ExpiredInterceptor> expiredInterceptors = new ConcurrentQueue<ExpiredInterceptor>();
4141

4242
/// <summary>
43-
/// 激活的记录
43+
/// 当前过期的拦截器的数量
4444
/// </summary>
45-
private volatile Lazy<ActiveEntry> activeEntryLazy;
46-
45+
private int expiredCount = 0;
4746

4847
/// <summary>
49-
/// 获取生命周期
48+
/// 激活的拦截器
5049
/// </summary>
51-
TimeSpan IHttpApiFactory.Lifetime
52-
{
53-
get => this.lifeTime;
54-
}
50+
private Lazy<ActiveInterceptor> activeInterceptorLazy;
5551

5652
/// <summary>
5753
/// HttpApi创建工厂
5854
/// </summary>
5955
public HttpApiFactory()
6056
{
61-
this.activeEntryLazy = new Lazy<ActiveEntry>(
62-
this.CreateActiveEntry,
57+
this.activeInterceptorLazy = new Lazy<ActiveInterceptor>(
58+
this.CreateActiveInterceptor,
6359
LazyThreadSafetyMode.ExecutionAndPublication);
64-
65-
this.RegisteCleanup();
6660
}
6761

68-
6962
/// <summary>
7063
/// 置HttpApi实例的生命周期
7164
/// </summary>
@@ -133,80 +126,88 @@ public TInterface CreateHttpApi()
133126
/// <returns></returns>
134127
object IHttpApiFactory.CreateHttpApi()
135128
{
136-
var interceptor = this.activeEntryLazy.Value.Interceptor;
129+
var interceptor = this.activeInterceptorLazy.Value;
137130
return HttpApiClient.Create(typeof(TInterface), interceptor);
138131
}
139132

140133
/// <summary>
141-
/// 创建激活状态的记录
134+
/// 创建激活状态的拦截器
142135
/// </summary>
143136
/// <returns></returns>
144-
private ActiveEntry CreateActiveEntry()
137+
private ActiveInterceptor CreateActiveInterceptor()
145138
{
146139
var handler = this.handlerFunc?.Invoke() ?? new DefaultHttpClientHandler();
147140
var httpApiConfig = new HttpApiConfig(handler, true);
148-
var interceptor = new LifeTimeTrackingInterceptor(httpApiConfig);
149141

150142
if (this.configAction != null)
151143
{
152144
this.configAction.Invoke(httpApiConfig);
153145
}
154146

155-
return new ActiveEntry(this)
156-
{
157-
Interceptor = interceptor,
158-
Disposable = httpApiConfig
159-
};
147+
return new ActiveInterceptor(
148+
httpApiConfig,
149+
this.lifeTime,
150+
this.OnInterceptorDeactivate);
160151
}
161152

162153
/// <summary>
163-
/// 当有记录失效时
154+
/// 当有拦截器失效时
164155
/// </summary>
165-
/// <param name="active">激活的记录</param>
166-
void IHttpApiFactory.OnEntryDeactivate(ActiveEntry active)
156+
/// <param name="active">激活的拦截器</param>
157+
private void OnInterceptorDeactivate(ActiveInterceptor active)
167158
{
168159
// 切换激活状态的记录的实例
169-
this.activeEntryLazy = new Lazy<ActiveEntry>(
170-
this.CreateActiveEntry,
160+
this.activeInterceptorLazy = new Lazy<ActiveInterceptor>(
161+
this.CreateActiveInterceptor,
171162
LazyThreadSafetyMode.ExecutionAndPublication);
172163

173-
var expired = new ExpiredEntry(active);
174-
this.expiredEntries.Enqueue(expired);
164+
var expired = new ExpiredInterceptor(active);
165+
this.expiredInterceptors.Enqueue(expired);
166+
167+
// 从0变为1,要启动清理作业
168+
if (Interlocked.Increment(ref this.expiredCount) == 1)
169+
{
170+
this.RegisteCleanup();
171+
}
175172
}
176173

177174

178175
/// <summary>
179176
/// 注册清理任务
180177
/// </summary>
181-
private void RegisteCleanup()
178+
private async void RegisteCleanup()
182179
{
183-
Task.Delay(this.cleanupInterval)
184-
.ConfigureAwait(false)
185-
.GetAwaiter()
186-
.OnCompleted(this.CleanupCallback);
180+
while (this.Cleanup() == false)
181+
{
182+
await Task.Delay(this.cleanupInterval).ConfigureAwait(false);
183+
}
187184
}
188185

189186
/// <summary>
190-
/// 清理任务回调
187+
/// 清理失效的拦截器
191188
/// </summary>
192-
private void CleanupCallback()
189+
/// <returns>是否完全清理</returns>
190+
private bool Cleanup()
193191
{
194-
var count = this.expiredEntries.Count;
195-
for (var i = 0; i < count; i++)
192+
var cleanCount = this.expiredInterceptors.Count;
193+
for (var i = 0; i < cleanCount; i++)
196194
{
197-
this.expiredEntries.TryDequeue(out var entry);
198-
if (entry.CanDispose == true)
195+
this.expiredInterceptors.TryDequeue(out var expired);
196+
if (expired.CanDispose == false)
199197
{
200-
entry.Dispose();
198+
this.expiredInterceptors.Enqueue(expired);
201199
}
202200
else
203201
{
204-
this.expiredEntries.Enqueue(entry);
202+
expired.Dispose();
203+
if (Interlocked.Decrement(ref this.expiredCount) == 0)
204+
{
205+
return true;
206+
}
205207
}
206208
}
207209

208-
209-
this.RegisteCleanup();
210+
return false;
210211
}
211212
}
212-
}
213+
}

WebApiClient/Internal/HttpApiFactories/ActiveEntry.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using WebApiClient.Defaults;
4+
5+
namespace WebApiClient
6+
{
7+
/// <summary>
8+
/// 表示激活状态的拦截器
9+
/// </summary>
10+
class ActiveInterceptor : ApiInterceptor
11+
{
12+
/// <summary>
13+
/// 激活状态的拦截器
14+
/// </summary>
15+
/// <param name="httpApiConfig">httpApi配置</param>
16+
/// <param name="lifeTime">生命周期</param>
17+
/// <param name="deactivateAction">生效委托</param>
18+
/// <exception cref="ArgumentNullException"></exception>
19+
public ActiveInterceptor(HttpApiConfig httpApiConfig, TimeSpan lifeTime, Action<ActiveInterceptor> deactivateAction)
20+
: base(httpApiConfig)
21+
{
22+
if (deactivateAction == null)
23+
{
24+
throw new ArgumentNullException(nameof(deactivateAction));
25+
}
26+
27+
Task.Delay(lifeTime)
28+
.ConfigureAwait(false)
29+
.GetAwaiter()
30+
.OnCompleted(() => deactivateAction(this));
31+
}
32+
33+
/// <summary>
34+
/// 这里不释放资源
35+
/// </summary>
36+
public sealed override void Dispose()
37+
{
38+
}
39+
}
40+
}

WebApiClient/Internal/HttpApiFactories/ExpiredEntry.cs renamed to WebApiClient/Internal/HttpApiFactories/ExpiredInterceptor..cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
namespace WebApiClient
44
{
55
/// <summary>
6-
/// 表示过期状态的记录
6+
/// 表示过期状态的拦截器
77
/// </summary>
8-
class ExpiredEntry : IDisposable
8+
class ExpiredInterceptor : IDisposable
99
{
1010
/// <summary>
1111
/// 用于释放资源的对象
@@ -27,13 +27,13 @@ public bool CanDispose
2727
}
2828

2929
/// <summary>
30-
/// 过期状态的记录
30+
/// 过期状态的拦截器
3131
/// </summary>
32-
/// <param name="active">激活状态的记录</param>
33-
public ExpiredEntry(ActiveEntry active)
32+
/// <param name="active">激活状态的拦截器</param>
33+
public ExpiredInterceptor(ActiveInterceptor active)
3434
{
35-
this.disposable = active.Disposable;
36-
this.weakReference = new WeakReference(active.Interceptor);
35+
this.disposable = active.HttpApiConfig;
36+
this.weakReference = new WeakReference(active);
3737
}
3838

3939
/// <summary>
Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
1-
using System;
2-
3-
namespace WebApiClient
1+
namespace WebApiClient
42
{
53
/// <summary>
64
/// 定义HttpApiFactory的接口
75
/// </summary>
86
interface IHttpApiFactory
97
{
10-
/// <summary>
11-
/// 获取生命周期
12-
/// </summary>
13-
TimeSpan Lifetime { get; }
14-
158
/// <summary>
169
/// 创建接口的代理实例
1710
/// </summary>
1811
/// <returns></returns>
19-
object CreateHttpApi();
20-
21-
/// <summary>
22-
/// 当有记录失效时
23-
/// </summary>
24-
/// <param name="entry">激活状态的记录</param>
25-
void OnEntryDeactivate(ActiveEntry entry);
12+
object CreateHttpApi();
2613
}
2714
}

WebApiClient/Internal/HttpApiFactories/LifeTimeTrackingInterceptor.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)