我把多个应用程序实例的问题上后面燃烧器。不是没关系,但是如果你是针对接口进行编程,那么在某些时候你可以用缓存的东西替换你的实现。
如果您希望平均请求时间超过五分钟的持续时间,那么您需要一个弹出过期条目的列表。下面是在一个刺:
internal class TimestampedEntry<T>
{
internal DateTimeOffset Timestamp { get; private set; }
internal T Value { get; private set; }
internal TimestampedEntry(T value)
{
Timestamp = DateTimeOffset.Now;
Value = value;
}
}
public class ExpiringList<T>
{
private readonly List<TimestampedEntry<T>> _list = new List<TimestampedEntry<T>>();
private readonly TimeSpan _expiration;
public ExpiringList(TimeSpan expiration)
{
_expiration = expiration;
}
public void Add(T item)
{
lock (_list)
{
_list.Add(new TimestampedEntry<T>(item));
}
}
public IReadOnlyCollection<T> Read()
{
var cutoff = DateTimeOffset.Now - _expiration;
TimestampedEntry<T>[] result;
lock (_list)
{
result = _list.Where(item => item.Timestamp > cutoff).ToArray();
_list.Clear();
_list.AddRange(result);
}
return new ReadOnlyCollection<T>(result.Select(item => item.Value).ToList());
}
}
这可确保当您从列表中读它只返回存储在指定的时间间隔内的项目,并删除其余的。您可以创建一个ExpiringList<TimeSpan>
,为每个呼叫添加已用时间,然后根据需要检查平均值。
在哪里存放它?我会把它放在一个单独的实例中。这可能是单身或静态类。我更喜欢使用返回单个实例的依赖注入容器(如Windsor's singleton lifestyle)。我不喜欢创建单例。我宁愿创建一个“普通”类,然后管理它以保持单个实例。像温莎这样的DI容器可以很容易地实现。
我认为在这样的实现中一个重要的因素是保持杂乱的切换逻辑分离 - 隐藏在某种工厂中,而不是使用if/then
所有逻辑来检查平均响应时间并调用任一API在一个大班上。
举例来说,如果你有代表呼吁得到的数据,像IMyDataProvider
的接口,那么你可以这样定义
interface IMyDataProviderFactory
{
IMyDataProvider Create();
}
你的类只取决于该工厂接口的工厂。执行IMyDataProviderFactory
的类将检查您的平均响应时间,并返回调用外部API的IMyDataProvider
的实现或使用您的计算的实现。
这样,该逻辑的复杂性就与依赖于API的任何类保持独立。
温莎与那些abstract factories也很好。其他DI容器也使它们变得简单,并且这种功能被内置到ASP.NET Core中。你并没有问及依赖注入,但我建议研究它。它可以更轻松地管理这种复杂性并保持可维护性。
回到多个应用程序实例和分布式缓存 - 您可以看到工厂模式实现如何更容易管理。假设今天这是一个例子,但明天你想通过分布式缓存共享这些数据。你在哪里做这个改变?大多数依赖于此API的代码根本不需要更改,因为它不会“知道”任何这些实现细节。您可以更改存储每个API调用时间的代码,并更改工厂的实施。
如果你有自己的实现,那么为什么你需要打电话给第三方?或者在几小时后致电第三方并将数据存储在某处,以便更快地获得数据。 –
数据在第三方“实时”更新,所以我想每次都调用它,除非它在最后几分钟内变得接近无响应。 – mitomed