What is a practical solution to a long running program? - memory-management

I have a .Net console application that is supposed to be long running and continous , basically 24 hours a day. It's for a rabbitmq consumer client. I am opening 30 channels on 1 connection, and each channel is responsible for 7 different queues.
Task creation:
tokenSource2 = new CancellationTokenSource();
cancellationToken = tokenSource2.Token;
for (int i = 0; i < 30; i++) //MAX 100 MODEL
{
List<string> partlist = tmpDBList.Take(7).ToList();
tmpDBList = tmpDBList.Except(partlist).ToList();
new Task(delegate { StartConsuming(partlist, cancellationToken); }, cancellationToken, TaskCreationOptions.LongRunning).Start();
}
The consumer method:
internal void StartConsuming(List<string> dbNames, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using (IModel channel = Consumer.CreateModel())
{
foreach (string item in dbNames)
{
//Queue creation, exchange declare, bind, + basic eventhandler etc..
channel.BasicConsume(queue: item,
autoAck: true,
consumer: consumerEvent);
}
cancellationToken.ThrowIfCancellationRequested();
while (!cancellationToken.IsCancellationRequested)
{
cancellationToken.WaitHandle.WaitOne(5000);
}
}
}
Since I want the task to never stop I have the endless while cycle at the end of the using statement, otherwise the task stops, and the channels are disposed.
while (!cancellationToken.IsCancellationRequested)
{
cancellationToken.WaitHandle.WaitOne(5000);
}
Is this a an optimal solution?
Furthermore, each consumer event handler creates a DbContext of a specific database inside the
EventingBasicConsumer consumerEvent = new EventingBasicConsumer(channel);
consumerEvent.Received += (sender, basicDeliveryEventArgs) =>
{
cancellationToken.ThrowIfCancellationRequested();
//dbContext creation
}
event handler. Will the memory be freed after the eventhandler is finished ? Do I need to Dispose of the dbcontext and each class I am using inside the eventhandler?

Related

How to properly implement location changes listener to xamarin forms?

I have a listener that captures the location every 10 seconds or 100 meters or so. I am using
xam.plugin.geolocator
to implement the listener. My problem is the location listener is not working(meaning the changes in location were not capturing or saved in the location cache) when my application is minimized or the application is opened but the phone is locked.
Here is my code:
async Task StartListening()
{
if (!CrossGeolocator.Current.IsListening)
{
var defaultgpsaccuracy = Convert.ToDouble(Preferences.Get("gpsaccuracy", String.Empty, "private_prefs"));
await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(10), defaultgpsaccuracy, false, new Plugin.Geolocator.Abstractions.ListenerSettings
{
ActivityType = Plugin.Geolocator.Abstractions.ActivityType.Other,
AllowBackgroundUpdates = true,
DeferLocationUpdates = true,
DeferralDistanceMeters = 1,
DeferralTime = TimeSpan.FromSeconds(1),
ListenForSignificantChanges = true,
PauseLocationUpdatesAutomatically = false
});
}
}
I place this code in the first view/page of my application in my login.xaml.cs
Here are my questions:
How can I implement the listener properly so that when the application minimized or the phone/device is locked it still captures the changes of location?
What is the best GPS settings I need to capture the changes in location faster and accurately? Right now, my current settings are capturing the location every 10 seconds or 100 meters.
First you need to init StartListening then create event handlers for position changes and error handling
public Position CurrentPosition { get; set; }
public event EventHandler PositionChanged;
Don't forget to init it in your constructor :
CurrentPosition = new Position();
await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(20), 10, true);
CrossGeolocator.Current.PositionChanged += PositionChanging;
CrossGeolocator.Current.PositionError += PositionError;
Functions :
`private void PositionChanging(object sender, PositionEventArgs e)
{
CurrentPosition = e.Position;
if (PositionChanged != null)
{
PositionChanged(this, null);
}
}
private void PositionError(object sender, PositionErrorEventArgs e)
{
Debug.WriteLine(e.Error);
}`
You can now call PositionChanged when ever you want the latest position
Don't forget to stop listening :
`public async Task StopListeningAsync()
{
if (!CrossGeolocator.Current.IsListening)
return;
await CrossGeolocator.Current.StopListeningAsync();
CrossGeolocator.Current.PositionChanged -= PositionChanging;
CrossGeolocator.Current.PositionError -= PositionError;
}`

Delayed dialog with resume handler

I have the following scenario I think I'm doing it wrong.
I have a RootDialog which calls a ResultDialog. The ResultDialog presents the user a list of results (using HeroCard).
The ResultDialog closes itself using context.Done(..) after the message was posted.
In the RootDialog- AfterResultDialog Resume handler I want to ask the user if he has found the matching result, using another dialog (NotificationDialog), but I want to do that after 30 seconds.
After some research, this seems like it must be done using proactive messages.
It this example, I found a way to post the NotificationDialog in a proactive way.
private async Task AfterResultDialog(IDialogContext context, IAwaitable<object> result)
{
var message = await result as IMessageActivity;
var conversationReference = context.Activity.ToConversationReference();
ConversationStarter.conversationReference = JsonConvert.SerializeObject(conversationReference);
t = new Timer(timerEvent);
t.Change(30000, Timeout.Infinite);
context.Wait<string>(NotificationDialogAfter);
}
public void timerEvent(object target)
{
t.Dispose();
ConversationStarter.Resume();
}
But the problem I have is that I'm interested in the result of this NotifcationDialog to know what the user wants to do next.
But all examples I found using proactive-messages do not regard the result of a proactive message with dialog:
public class ConversationStarter
{
public static string conversationReference;
public static async Task Resume()
{
var message = JsonConvert.DeserializeObject<ConversationReference>(conversationReference).GetPostToBotMessage();
var client = new ConnectorClient(new Uri(message.ServiceUrl));
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(CancellationToken.None);
var task = scope.Resolve<IDialogTask>();
// here it seems only to be possible to call a dialog using Void
var dialog = new NotificationDialog();
task.Call(dialog.Void<object, IMessageActivity>(), null);
await task.PollAsync(CancellationToken.None);
await botData.FlushAsync(CancellationToken.None);
}
}
}
The NotificationDialogAfter handler should decide based on the user input which dialog to call next:
private async Task NotificationDialogAfter(IDialogContext context, IAwaitable<string> result)
{
var whereToContinue = await result;
if (whereToContinue.Equals("Start over"))
{
context.ClearAllConversationDataKeys();
context.Call(new TagDialog(), this.TagDialogAfter);
}
else if (whereToContinue == "Tell friends")
{
context.Call(new TellFriendsDialog(), TellFriendsDialogAfter);
}
else if (whereToContinue == "Feedback")
{
context.Call(new FeedbackDialog(), this.FeedbackDialogAfter);
}
}
So what I basically want is that the result of the NotificationDialog is forwarded to the NotificationDialogAfter handler which the Root dialog is waiting for.
Is this even possible?
I solve the problem by defining static continue handlers (in GlobalContinueHandler), that I can provide inside the NotificationDialog, when calling other dialogs.
[Serializable]
public class NotificationDialog : IDialog<string>
{
public Task StartAsync(IDialogContext context)
{
PromptDialog.Choice(context, Resume, new List<string> { "yes", "no" },
"Found what you're looking for?");
return Task.CompletedTask;
}
private async Task Resume(IDialogContext context, IAwaitable<string> result)
{
var message = await result;
if (message == "yes")
{
context.Call(new SignupDialog(), GlobalContinueHandler.SignupDialogAfter);
}
else
{
context.Call(new FeedbackDialog(), GlobalContinueHandler.FeedbackDialogAfter);
}
}
}
I'm really not fan of this solution but for now it seems to work.

Reactive Extensions subscribing to an observable (subject)

I'm just playing around with Reactive Extensions for the first time in a winforms application. Mind you I have been doing web development for the past 4 years, and I am very familiar with observables and observable pattern in knockout, which I am guessing is contributing to my confusion here.
Anyhow, to the question and code. I have a simple winforms experiment (see below) that I was building to illustrate my question. The subscribe below doesn't run until well after the thread in start new is finished. I can trace it the calls to OnNext, but the subscribe doesn't fire at all until sometimes 20-30 seconds later. Can somebody explain this behavior to me?
public partial class Form1 : Form
{
private Subject<int> progress;
private CancellationToken cancellationToken;
private IScheduler _scheduler;
public Form1()
{
InitializeComponent();
CancellationTokenSource source = new CancellationTokenSource();
cancellationToken = source.Token;
_scheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);
}
private void Start_Click(object sender, EventArgs e)
{
progress
.ObserveOn(_scheduler)
//.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
(i) => {
progressBar1.Do<ProgressBar>(ctl =>
{
ctl.Value = i;
});
},
(ex) => { },
cancellationToken
);
Task counterTask = Task.Factory.StartNew(() =>
{
for (var i = 1; i < 101; i++)
{
Thread.Sleep(500);
progress.OnNext(i);
}
}, cancellationToken,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext()
);
}
private void Form1_Load(object sender, EventArgs e)
{
progress = new Subject<int>();
}
}
public static class ControlExtensions
{
public static void Do<TControl>(this TControl control, Action<TControl> action)
where TControl : Control
{
if (control.InvokeRequired)
control.Invoke(action, control);
else
action(control);
}
}
Your issue comes from the fact that your task is running on the UI thread, because you're using TaskScheduler.FromCurrentSynchronizationContext().
Hence your various Sleep calls are blocking the UI thread, freezing the UI (e.g. can't drag the window) and preventing your observable subscription to execute (because the ObserveOn, it's supposed to execute on the UI thread scheduler).
Replace TaskScheduler.FromCurrentSynchronizationContext() by TaskScheduler.Default (background TaskPool threads), and everything will work as you expected.
Note that your call to Do/Invoke is unnecessary, because you're already on the UI thread by the scheduler you've provided.

PushStreamContent stream does not flush under load

I am using PushStreamContent to keep a persistent connection to each client. Pushing short heartbeat messages to each client stream every 20 seconds works great with 100 clients, but at about 200 clients, the client first starts receiving it a few seconds delayed, then it doesn't show up at all.
My controller code is
// Based loosely on https://aspnetwebstack.codeplex.com/discussions/359056
// and http://blogs.msdn.com/b/henrikn/archive/2012/04/23/using-cookies-with-asp-net-web-api.aspx
public class LiveController : ApiController
{
public HttpResponseMessage Get(HttpRequestMessage request)
{
if (_timer == null)
{
// 20 second timer
_timer = new Timer(TimerCallback, this, 20000, 20000);
}
// Get '?clientid=xxx'
HttpResponseMessage response = request.CreateResponse();
var kvp = request.GetQueryNameValuePairs().Where(q => q.Key.ToLower() == "clientid").FirstOrDefault();
string clientId = kvp.Value;
HttpContext.Current.Response.ClientDisconnectedToken.Register(
delegate(object obj)
{
// Client has cleanly disconnected
var disconnectedClientId = (string)obj;
CloseStreamFor(disconnectedClientId);
}
, clientId);
response.Content = new PushStreamContent(
delegate(Stream stream, HttpContent content, TransportContext context)
{
SaveStreamFor(clientId, stream);
}
, "text/event-stream");
return response;
}
private static void CloseStreamFor(string clientId)
{
Stream oldStream;
_streams.TryRemove(clientId, out oldStream);
if (oldStream != null)
oldStream.Close();
}
private static void SaveStreamFor(string clientId, Stream stream)
{
_streams.TryAdd(clientId, stream);
}
private static void TimerCallback(object obj)
{
DateTime start = DateTime.Now;
// Disable timer
_timer.Change(Timeout.Infinite, Timeout.Infinite);
// Every 20 seconds, send a heartbeat to each client
var recipients = _streams.ToArray();
foreach (var kvp in recipients)
{
string clientId = kvp.Key;
var stream = kvp.Value;
try
{
// ***
// Adding this Trace statement and running in debugger caused
// heartbeats to be reliably flushed!
// ***
Trace.WriteLine(string.Format("** {0}: Timercallback: {1}", DateTime.Now.ToString("G"), clientId));
WriteHeartBeat(stream);
}
catch (Exception ex)
{
CloseStreamFor(clientId);
}
}
// Trace... (this trace statement had no effect)
_timer.Change(20000, 20000); // re-enable timer
}
private static void WriteHeartBeat(Stream stream)
{
WriteStream(stream, "event:heartbeat\ndata:-\n\n");
}
private static void WriteStream(Stream stream, string data)
{
byte[] arr = Encoding.ASCII.GetBytes(data);
stream.Write(arr, 0, arr.Length);
stream.Flush();
}
private static readonly ConcurrentDictionary<string, Stream> _streams = new ConcurrentDictionary<string, Stream>();
private static Timer _timer;
}
Could there be some ASP.NET or IIS setting that affects this? I am running on Windows Server 2008 R2.
UPDATE:
Heartbeats are reliably sent if 1) the Trace.WriteLine statement is added, 2) Visual Studio 2013 debugger is attached and debugging and capturing the Trace.WriteLines).
Both of these are necessary; if the Trace.WriteLine is removed, running under the debugger has no effect. And if the Trace.WriteLine is there but the program is not running under the debugger (instead SysInternals' DbgView is showing the trace messages), the heartbeats are unreliable.
UPDATE 2:
Two support incidents with Microsoft later, here are the conclusions:
1) The delays with 200 clients were resolved by using a business class Internet connection instead of a Home connection
2) whether the debugger is attached or not really doesn't make any difference;
3) The following two additions to web.config are required to ensure heartbeats are sent timely, and failed heartbeats due to client disconnecting "uncleanly" (e.g. by unplugging computer rather than normal closing of program which cleanly issues TCP RST) trigger a timely ClientDisconnected callback as well:
<httpRuntime executionTimeout="5" />
<serverRuntime appConcurrentRequestLimit="50000" uploadReadAheadSize="1" frequentHitThreshold="2147483647" />

Alternatives for WaitHandle.WaitAll on Windows Phone?

WaitHandle.WaitAll throws a NotSupportedException when executed on Windows Phone (7.1). Is there an alternative to this method?
Here's my scenario: I am firing off a bunch of http web requests and I want to wait for all of them to return before I can continue. I want to make sure that if the user has to wait for more than X seconds (in total) for all of these requests to return, the operation should be aborted.
You can try with a global lock.
Start a new thread, and use a lock to block the caller thread, with the timeout value you want.
In the new thread, loop on the handles and call wait on each. When the loop is done, signal the lock.
Something like:
private WaitHandle[] handles;
private void MainMethod()
{
// Start a bunch of requests and store the waithandles in the this.handles array
// ...
var mutex = new ManualResetEvent(false);
var waitingThread = new Thread(this.WaitLoop);
waitingThread.Start(mutex);
mutex.WaitOne(2000); // Wait with timeout
}
private void WaitLoop(object state)
{
var mutex = (ManualResetEvent)state;
for (int i = 0; i < handles.Length; i++)
{
handles[i].WaitOne();
}
mutex.Set();
}
Another version using Thread.Join instead of a shared lock:
private void MainMethod()
{
WaitHandle[] handles;
// Start a bunch of requests and store the waithandles in the handles array
// ...
var waitingThread = new Thread(this.WaitLoop);
waitingThread.Start(handles);
waitingThread.Join(2000); // Wait with timeout
}
private void WaitLoop(object state)
{
var handles = (WaitHandle[])state;
for (int i = 0; i < handles.Length; i++)
{
handles[i].WaitOne();
}
}

Resources