Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/rest/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在Web API中维护请求的状态或队列_C#_Asp.net_Solr_Asp.net Web Api_Solrnet - Fatal编程技术网

C# 如何在Web API中维护请求的状态或队列

C# 如何在Web API中维护请求的状态或队列,c#,asp.net,solr,asp.net-web-api,solrnet,C#,Asp.net,Solr,Asp.net Web Api,Solrnet,在这种情况下,我必须在一个WebAPI方法中接收请求,对这些请求进行排队,然后将批量发送到一个数据库(Solr实例) 我不确定如何维护来自多个来源的一批请求。现在,我正在以json格式将每个请求数据写入磁盘上的一个文件,稍后我将使用windows服务,遍历文件夹读取所有文件,更新数据库并删除这些文件 下面是我在我的Web API中所做的 public void Post(LogEntry value) { value.EventID = Guid.NewGuid(); value

在这种情况下,我必须在一个WebAPI方法中接收请求,对这些请求进行排队,然后将批量发送到一个数据库(Solr实例)

我不确定如何维护来自多个来源的一批请求。现在,我正在以json格式将每个请求数据写入磁盘上的一个文件,稍后我将使用windows服务,遍历文件夹读取所有文件,更新数据库并删除这些文件

下面是我在我的Web API中所做的

public void Post(LogEntry value)
{
    value.EventID = Guid.NewGuid();
    value.ServerTime = DateTime.UtcNow;
    string json = JsonConvert.SerializeObject(value);
    using(StreamWriter sw = new StreamWriter(value.EventID.ToString()))
    {
        sw.Write(json);
    }
}
(此处
EventID
为GUID)

这个过程看起来不正确,必须有一种方法来维护请求队列,但我不确定如何在多个请求期间维护队列


我这样做的原因是,在solr实例中批量插入比通过SolrNet插入单个记录更快。我希望在Web API上每秒至少收到100个请求。我想创建一批1000个请求,并每10秒更新一次solr实例。请不要认为我需要代码,只需要知道我应该采取什么策略来维护请求/状态队列

如果您使用的是.NET 4.0或更高版本,则可以使用并发队列:

这是一种使用队列的线程安全方式,然后可以在所需时间访问队列

编辑:

例如:

这将是队列的包装器:

public static class RequestQueue
{
    private static ConcurrentQueue<int> _queue;

    public static ConcurrentQueue<int> Queue
    {
        get
        {
            if (_queue == null)
            {
                _queue = new ConcurrentQueue<int>();
            }

            return _queue;
        }
    }

}
如果使用此示例,您将看到队列跨多个请求保存值。但是,由于它存在于内存中,因此如果应用程序池被回收(例如),那些排队的项目将消失

现在,您可以在创建另一个队列以存储传入值的同时,检查队列何时包含10个项目,然后将这些项目保存到数据库中

像这样:

public static class RequestQueue
{
    private static ConcurrentQueue<int> _queue;

    public static ConcurrentQueue<int> Queue
    {
        get
        {
            if (_queue == null)
            {
                _queue = new ConcurrentQueue<int>();
            }

            if (_queue.Count >= 10)
            {
                SaveToDB(_queue);
                _queue = new ConcurrentQueue<int>();
            }

            return _queue;
        }
    }

    public static void SaveToDB(ConcurrentQueue<int> queue)
    {
        foreach (var item in queue)
        {
            SaveItemToDB(item);
        }
    }
}
公共静态类请求队列
{
私有静态ConcurrentQueue\u队列;
公共静态并发队列
{
得到
{
如果(_queue==null)
{
_队列=新的ConcurrentQueue();
}
如果(_queue.Count>=10)
{
SaveToDB(_队列);
_队列=新的ConcurrentQueue();
}
返回队列;
}
}
公共静态void SaveToDB(ConcurrentQueue队列)
{
foreach(队列中的变量项)
{
SaveItemToDB(项目);
}
}
}

您需要稍微清理一下,但是这个设置应该可以工作。此外,在将队列转储到数据库和创建新实例时,可能需要一些锁定机制。我将编写一个控制台应用程序,其中有多个线程访问此队列以对其进行测试。

您可以将请求排入内存中的队列,并使用Quartz.Net定期将它们发送到数据库。您只需在Global.asax.cs中进行如下操作:

public class RequestQueue
{
    private readonly Queue<HttpRequest> _requestHistory; 
    private RequestQueue()
    {
        _requestHistory = new Queue<HttpRequest>();
    }
    private static RequestQueue _singleton;

    public static RequestQueue Instance()
    {
        if (_singleton == null)
            _singleton = new RequestQueue();
        return _singleton;
    }

    public void Enqueue(HttpRequest request)
    {
        _requestHistory.Enqueue(request);
    }

    public void Flush()
    {
        while (_requestHistory.Count > 0)
        {
            var request = _requestHistory.Dequeue();
            try
            {
                //Write request To Db
            }
            catch (Exception)
            {
                _requestHistory.Enqueue(request);
            }
        }
    }
}

public class WebApiApplication : System.Web.HttpApplication
{
    public WebApiApplication()
    {
        base.BeginRequest += delegate
            {
                RequestQueue.Instance().Enqueue(HttpContext.Current.Request);
            };
    }

    private void InitializeQuartz()
    {
        ISchedulerFactory sf = new StdSchedulerFactory();
        IScheduler sched = sf.GetScheduler();

        DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTime.UtcNow);
        DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 5);

        IJobDetail job = JobBuilder.Create<QueueConsumer>()
            .WithIdentity("job1", "group1")
            .Build();
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("trigger1", "group1")
            .StartAt(runTime)
            .WithCronSchedule("5 0/1 * * * ?")
            .Build();

        sched.ScheduleJob(job, trigger);

        sched.Start();
    }

    public class QueueConsumer : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            RequestQueue.Instance().Flush();
        }
    }

    protected void Application_Start()
    {
        InitializeQuartz();
公共类请求队列
{
私有只读队列_requestHistory;
私有请求队列()
{
_requestHistory=新队列();
}
私有静态请求队列_singleton;
公共静态RequestQueue实例()
{
如果(_singleton==null)
_singleton=newrequestqueue();
返回单件;
}
公共无效排队(HttpRequest请求)
{
_requestHistory.Enqueue(请求);
}
公共图书馆
{
而(_requestHistory.Count>0)
{
var request=_requestHistory.Dequeue();
尝试
{
//向数据库写入请求
}
捕获(例外)
{
_requestHistory.Enqueue(请求);
}
}
}
}
公共类WebAPI应用程序:System.Web.HttpApplication
{
公共WebAPI应用程序()
{
base.BeginRequest+=委托
{
RequestQueue.Instance().Enqueue(HttpContext.Current.Request);
};
}
私有void InitializeQuartz()
{
isSchedulerFactory sf=新StdSchedulerFactory();
isScheduler sched=sf.GetScheduler();
DateTimeOffset运行时=DateBuilder.EvenMinuteDate(DateTime.UtcNow);
DateTimeOffset startTime=DateBuilder.NextGivenSecondDate(null,5);
IJobDetail job=JobBuilder.Create()
.WithIdentity(“工作1”、“组1”)
.Build();
ITrigger trigger=TriggerBuilder.Create()
.WithIdentity(“触发器1”、“组1”)
.StartAt(运行时)
.随附附件(“50/1***?”)
.Build();
sched.ScheduleJob(作业,触发器);
sched.Start();
}
公共类排队消费者:IJob
{
public void Execute(IJobExecutionContext上下文)
{
RequestQueue.Instance().Flush();
}
}
受保护的无效应用程序\u Start()
{
InitializeQuartz();

另一种解决方案是将记录保存在内存队列中,该队列与WebApi的进程不同。例如:MemcacheQueue


其中一些队列实现具有持久性功能,因此您在任何情况下都不会丢失数据。

您应该尝试实现具有调度消息和在将来发送消息的功能,从服务总线文档中,您可以调度功能您可以调度任务或操作/lambda在给定的时间间隔内重复执行。

这意味着您可以拥有memeory缓存,并每10分钟将阵列内容写入solr/lucene impl,例如,这非常简单:

Schedule.Every(TimeSpan.FromMinutes(10)).Action(() => { < task to be executed > })
Schedule.Every(TimeSpan.FromMinutes(10)).Action(()=>{})
如果您需要更大的灵活性来设置schedueler,您可以将其集成到quartz.net中

具体情况如下:

  • WCF as windows服务和NServiceBus应该共享相同的上下文,或者实现可以在系统的这两个不同部分之间共享的cacheManager<
    Schedule.Every(TimeSpan.FromMinutes(10)).Action(() => { < task to be executed > })
    
    public class ThresholdBuffer<T>
    {
        private ConcurrentBag<T> _buffer;
    
        private int _threshold;
    
        public ThresholdBuffer(int threshold)
        {
            _threshold = threshold;
            _buffer = new ConcurrentBag<T>();
        }
    
        public void Add(T item)
        {
            _buffer.Add(item);
    
            if(_buffer.Count >= _threshold)
            {
                Recycle();
            }
        }
    
        public void Recycle()
        {
            var value = Interlocked.Exchange<ConcurrentBag<T>>(ref _buffer, new ConcurrentBag<T>());
    //flush value 
        }
    }
    
    public class ThresholdBuffer<T>
    {
        private ConcurrentBag<T> _buffer;
    
        private int _copacity;
    
        private int _threshold;
    
        public ThresholdBuffer(int threshold)
        {
            _threshold = threshold;
            _copacity = 0;
            _buffer = new ConcurrentBag<T>();
        }
    
        public void Add(T item)
        {
            _buffer.Add(item);
            if (Interlocked.Increment(ref _copacity) == _threshold)
            {
                Recycle();
            }
        }
    
        public void Recycle()
        {
            var value4flasshing = Interlocked.Exchange<ConcurrentBag<T>>(ref _buffer, new ConcurrentBag<T>());
            Thread.VolatileWrite(ref _copacity, 0);
        }
    }