MVC 5 - Ninject - Tasks Thread Running Oddly - c#

I have a thread that shoots events to run programs at certain times.
I do want the website to have full control over the process so that is why I built it into the site as a long term thread that loops.
The issue is I scheduled a task to happen at a particular time and it happens almost randomly (maybe when I load the page). It seems as if the web app sleeps all threads until its used or something.
Here is the code:
public void run()
{
Task.Factory.StartNew(() =>
{
while (true)
{
var lastDate = InternalEventLogger.GetLastDateTime();
if (DateTime.Now >= lastDate.AddDays(1))
{
System.Diagnostics.Debug.WriteLine(DateTime.Now);
System.Diagnostics.Debug.WriteLine(lastDate.AddDays(1));
InternalEventLogger.RefreshLog();
}
bool needUpdate = false;
System.Diagnostics.Debug.WriteLine("this");
List<Event> tempList = new List<Event>(this.evtList.getList());
foreach (Event evt in this.evtList.getList())
{
if (!evt.status.Equals("success"))
continue;
if (evt.nextRun <= DateTime.Now)
{
var tempEvt = evt;
System.Diagnostics.Debug.WriteLine("time to run: "+evt.name);
tempList.Remove(evt);
tempEvt.nextRun = evt.nextRun.AddMinutes(evt.interval);
tempEvt.lastRan = DateTime.Now;
tempList.Add(tempEvt);
needUpdate = true;
if (tempEvt.runLocation != null)
Task.Factory.StartNew(() =>
{
Process p = new Process();
p.StartInfo.FileName = tempEvt.runLocation;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string err = p.StandardError.ReadToEnd();
InternalEventLogger.WriteLog(output);
InternalEventLogger.WriteLog("// ------------- ERROR -------------- \n" + err);
p.WaitForExit();
});
}
}
if (needUpdate)
{
this.evtList.setList(tempList);
this.evtList.serialize(ConfigurationManager.AppSettings["xmlEventLocation"]);
}
Thread.Sleep(10000);
}
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
Ran from:
private static void RegisterServices(IKernel kernel)
{
evtManager = new EventManager(ConfigurationManager.AppSettings["xmlEventLocation"]);
evtManager.run();
// Initalize Event Logger
new InternalEventLogger();
}
Here is a pic that shows the problem in timing:
UPDATE
Tried the settings below and still not working properly!
Only at visit does it start the tasks.

May be problem in your IIS web server settings. IIS Application Pool have parameter (in advanced settings): Idle Time-out (minutes). By default this settings is 20 minutes. So when there are no queries to web site during 20 minutes web server stops Application Pool process.
Idle Time-out parameter explanation.
Link to Microsoft Technet

Recycling timer on IIS Settings needed to be changed.

Related

MVC 5 - IIS Stops Tasks Thread

I have a thread that shoots events to run programs at certain times.
I do want the website to have full control over the process so that is why I built it into the site as a long term thread that loops.
The issue is I scheduled a task to happen at a particular time and it happens almost randomly (maybe when I load the page). It seems as if the web app sleeps all threads until its used or something.
Here is the code:
public void run()
{
Task.Factory.StartNew(() =>
{
while (true)
{
var lastDate = InternalEventLogger.GetLastDateTime();
if (DateTime.Now >= lastDate.AddDays(1))
{
System.Diagnostics.Debug.WriteLine(DateTime.Now);
System.Diagnostics.Debug.WriteLine(lastDate.AddDays(1));
InternalEventLogger.RefreshLog();
}
bool needUpdate = false;
System.Diagnostics.Debug.WriteLine("this");
List<Event> tempList = new List<Event>(this.evtList.getList());
foreach (Event evt in this.evtList.getList())
{
if (!evt.status.Equals("success"))
continue;
if (evt.nextRun <= DateTime.Now)
{
var tempEvt = evt;
System.Diagnostics.Debug.WriteLine("time to run: "+evt.name);
tempList.Remove(evt);
tempEvt.nextRun = evt.nextRun.AddMinutes(evt.interval);
tempEvt.lastRan = DateTime.Now;
tempList.Add(tempEvt);
needUpdate = true;
if (tempEvt.runLocation != null)
Task.Factory.StartNew(() =>
{
Process p = new Process();
p.StartInfo.FileName = tempEvt.runLocation;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string err = p.StandardError.ReadToEnd();
InternalEventLogger.WriteLog(output);
InternalEventLogger.WriteLog("// ------------- ERROR -------------- \n" + err);
p.WaitForExit();
});
}
}
if (needUpdate)
{
this.evtList.setList(tempList);
this.evtList.serialize(ConfigurationManager.AppSettings["xmlEventLocation"]);
}
Thread.Sleep(10000);
}
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
Ran from:
private static void RegisterServices(IKernel kernel)
{
evtManager = new EventManager(ConfigurationManager.AppSettings["xmlEventLocation"]);
evtManager.run();
// Initalize Event Logger
new InternalEventLogger();
}
Here is a pic that shows the problem in timing:
IIS Settings below
Only at visit does it start the tasks.
Open that settings dialog in your IIS Manager.
Make sure you have:
Start Mode = AlwaysRunning
Idle Time-out (minutes) = 0
for the application pool you are using - test the settings so that you are sure you are editing the correct pool.
If you have this, your application should be running all the time, but there is one more thing - Recycling - at the bottom of that setting dialog, set up your Recycling as you need it. It might be the case that you are OK with the defaults, but if you are not aware of Recycling, it might surprise you, so make sure you understand it and configure the settings as you need it.
Yes, you are right, the IIS hosting do not stores the threads, as all the Web Application has to do is handle the request and provide the response. If you want to run the task on schedule, you really shouldn't use the web application, as it cancels all the background threads after the response is sent.
I suggest you to change your architecture, and create a Windows service (like daemon) which will start automatically after system boot, and which can much more easily control the event firing.
If for somewhat reason you want a web interface for such method, you can use a WCF binding between your web application and windows service (over TCP/IP or named pipes or whatever), but your approach wouldn't work for Web Application.
I want also to point out that this code:
while (true)
is a bad idea - you should use a CancellationToken for your task in this case.

Windows Service stuck on "starting" status as local system account

I developed a http server via console application in C# and decided to turn it into a Windows service to be able to initialize it without the need to login the machine.
I followed all the steps in How to create Windows Service and chose the account as "Local System", but when I install in my server machine and push the start button it takes a while and gives the following error:
Erro 1053: The service did not respond to the start or control request in timely fashion.
After that, the service status stays stuck in "starting" and the application don't work and I can't even stop the service anymore.
Trying to work around this problem, I changed it to "Network Service", so it started normally, but the application was not listening in the port I set when I checked in the prompt with the command "netstat -an". But the application listens normally if i run it as a console application.
So I am looking for an answer to one of these two questions:
What should I do to make the service starts properly with a Local System account?
If I decide to use Network service account, what should I care about to guarantee that my service works properly as a server?
When I converted my console application to windows service I simply put my code directly in the OnStart method. However, I realized the OnStart method should start the service, but needs to end some time to the service indeed start. So I created a thread that runs my service and let the OnStart method finish. I tested and the service worked just fine. Here is how it was the code:
protected override void OnStart(string[] args)
{
Listener(); // this method never returns
}
Here is how it worked:
protected override void OnStart(string[] args)
{
Thread t = new Thread(new ThreadStart(Listener));
t.Start();
}
But I still don't understand why the service ran (passed the "starting" status, but didn't work) when I used network service account. If anyone knows, I'll be glad to know the reason.
If you have a service that is not responding or showing pending in Windows services that you are unable to stop, use the following directions to force the service to stop.
Start -> Run or Start -> type services.msc and press Enter
Look for the service and check the Properties and identify its service name
Once found, open a command prompt. Type sc queryex [servicename]
Identify the PID (process ID)
In the same command prompt type taskkill /pid [pid number] /f
Find PID of Service
sc queryex <SERVICE_NAME>
Give result's below
SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 3976 FLAGS :
Now Kill the Service:
taskkill /f /pid 3976
SUCESS: The process with PID 3976 has been terminated.
Check the Windows Application event log, it could contain some entries from your service's auto generated event source (which should have the same name of the service).
For me it was a while loop that looked at an external queue. The while-loop continued running until the queue was empty. Solved it by calling a timer event directly only when Environment.UserInteractive. Therefore the service could be debugged easily but when running as a service it would wait for the timers ElapsedEventHandler event.
Service:
partial class IntegrationService : ServiceBase
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private System.Timers.Timer timer;
public IntegrationService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
// Add code here to start your service.
logger.Info($"Starting IntegrationService");
var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
var updateInterval = 60000;
Int32.TryParse(updateIntervalString, out updateInterval);
var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
var projectDbContext = new ProjectDbContext();
var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
timer = new System.Timers.Timer();
timer.AutoReset = true;
var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
timer.Start();
}
catch (Exception e)
{
logger.Fatal(e);
}
}
protected override void OnStop()
{
try
{
// Add code here to perform any tear-down necessary to stop your service.
timer.Enabled = false;
timer.Dispose();
timer = null;
}
catch (Exception e)
{
logger.Fatal(e);
}
}
}
Processor:
public class IntegrationProcessor
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private static volatile bool _workerIsRunning;
private int _updateInterval;
private ProjectIntegrationService _projectIntegrationService;
public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
{
_updateInterval = updateInterval;
_projectIntegrationService = projectIntegrationService;
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = _updateInterval;
//Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
if (Environment.UserInteractive)
{
OnTimedEvent(null, null);
}
_workerIsRunning = false;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
try
{
if (_workerIsRunning == false)
{
_workerIsRunning = true;
ProjectInformationToGet infoToGet = null;
_logger.Info($"Started looking for information to get");
//Run until queue is empty
while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
{
//Set debugger on logger below to control how many cycles the service should run while debugging.
var watch = System.Diagnostics.Stopwatch.StartNew();
_logger.Info($"Started Stopwatch");
_logger.Info($"Found new information, updating values");
_projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
_logger.Info($"Completed updating values");
watch.Stop();
_logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
$"Name queue items: {infoToGet.NameQueueItems.Count} " +
$"Case queue items: {infoToGet.CaseQueueItems.Count} " +
$"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
$"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
}
_logger.Info($"Nothing more to get from integration service right now");
_workerIsRunning = false;
}
else
{
_logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
}
}
catch (DbEntityValidationException exception)
{
var newException = new FormattedDbEntityValidationException(exception);
HandelException(newException);
throw newException;
}
catch (Exception exception)
{
HandelException(exception);
//If an exception occurs when running as a service, the service will restart and run again
if (Environment.UserInteractive)
{
throw;
}
}
}
private void HandelException(Exception exception)
{
_logger.Fatal(exception);
_workerIsRunning = false;
}
}
You can try to increase the windows service timeout with a key in the registry
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
"ServicesPipeTimeout"=dword:300000 (300 seconds or 5 minutes)
If it doesn't exists it has to be created.

Long running task in workflow foundation 4

I have an application in which there are long running process, to handle that i have used Windows Workflow4
Process depends on number of users
If number of users are less i.e. 30-100 then it is working fine and if greater than 500 then there is problem
My problem is even if the Workflow process is completed View is showing processing but in backend it is completed
Workflow code
WorkflowApplication application;
application = new WorkflowApplication(new Payroll_Workflow.PayrollProcess(), inputparam);
application.SynchronizationContext = new SynchronousSynchronizationContext();
//we assign a delegate for the Completed event of the application
application.Completed = delegate(WorkflowApplicationCompletedEventArgs completedEvent)
{
if (completedEvent.TerminationException != null)
{
communicationMessage.message = completedEvent.TerminationException.Message.Replace("_", " ");
//ErrorMessages error = (ErrorMessages)Enum.Parse(typeof(ErrorMessages), completedEvent.TerminationException.Message.Replace(" ", "_"));
}
else
{
communicationMessage.message = "Process Completed";
}
};
//we start the application
application.Run();
Are your workflows all reaching "communicationMessage.message = "Process Completed";" ?
If they are then perhaps this communication process is being overwhelmed?

C# - Accessing the STDIN and STDOUT handles of a process without redirecting them

I'm trying to access the input and output streams of a process my application starts. My code is:
this.App = new Process();
this.App.StartInfo.FileName = this.AppPath;
this.App.StartInfo.Arguments = this.AppArgs;
this.App.StartInfo.RedirectStandardOutput = true;
this.App.StartInfo.UseShellExecute = false;
this.App.Start();
ThreadStart ts = new ThreadStart(() =>
{
while (true)
{
if (this.App.StandardOutput != null && !this.App.StandardOutput.EndOfStream)
{
Console.Write((char)this.App.StandardOutput.Read());
}
}
}
this.listener = new Thread(ts);
this.listener.IsBackground = true;
this.listener.Start();
this.App.WaitForExit();
The code does work perfectly. It prints any output of the spawned process into console. The problem is, that the spawned process is a Source Dedicated Server, which doesn't like when it's STDIN/STDERR/STDOUT handles are redirected - throws up an error MessageBox and dies once it's closed. I have spent hours trying to mess with kernel32.dll, but failed.
I'm looking for a way to access the handles/output of the spawned process without redirecting them, as I'm obviously not allowed to do that.
Anyone?
Please.

Process.Start is blocking

I'm calling Process.Start, but it blocks the current thread.
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
Even when the process is closed, the code doesn't respond anymore.
But Process.Start is really supposed to block? What's going on?
(The process start correctly)
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace Test
{
class Test
{
[STAThread]
public static void Main()
{
Thread ServerThread = new Thread(AccepterThread);
ServerThread.Start();
Console.WriteLine (" --- Press ENTER to stop service ---");
while (Console.Read() < 0) { Application.DoEvents(); }
Console.WriteLine("Done.");
}
public static void AccepterThread(object data)
{
bool accepted = false;
while (true) {
if (accepted == false) {
Thread hThread = new Thread(HandlerThread);
accepted = true;
hThread.Start();
} else
Thread.Sleep(100);
}
}
public static void HandlerThread(object data)
{
ProcessStartInfo pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
Console.WriteLine("Starting process.");
// Start process
Process mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Console.WriteLine("Unable to run process.");
}
Console.WriteLine("Still living...");
}
}
}
Console output is:
--- Press ENTER to stop service ---
Starting process.
Found it:
[STAThread]
Makes the Process.Start blocking. I read STAThread and Multithreading, but I cannot link the concepts with Process.Start behavior.
AFAIK, STAThread is required by Windows.Form. How to workaround this problem when using Windows.Form?
News for the hell:
If I rebuild my application, the first time I run application work correctly, but if I stop debugging and restart iy again, the problem araise.
The problem is not raised when application is executed without the debugger.
No, Process.Start doesn't wait for the child process to complete... otherwise you wouldn't be able to use features like redirected I/O.
Sample console app:
using System;
using System.Diagnostics;
public class Test
{
static void Main()
{
Process p = new Process {
StartInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe")
};
p.Start();
Console.WriteLine("See, I'm still running");
}
}
This prints "See, I'm still running" with no problems on my box - what's it doing on your box?
Create a ProcessStartInfo and set UseShellExecute to false (default value is true). Your code should read:
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
pInfo.UseShellExecute = false;
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
I had the same issue and starting the executable creating the process directly from the executable file solved the issue.
I was experiencing the same blocking behavior as the original poster in a WinForms app, so I created the console app below to simplify testing this behavior.
Jon Skeet's example uses Notepad, which only takes a few milliseconds to load normally, so a thread block may go unnoticed. I was trying to launch Excel which usually takes a lot longer.
using System;
using System.Diagnostics;
using static System.Console;
using System.Threading;
class Program {
static void Main(string[] args) {
WriteLine("About to start process...");
//Toggle which method is commented out:
//StartWithPath(); //Blocking
//StartWithInfo(); //Blocking
StartInNewThread(); //Not blocking
WriteLine("Process started!");
Read();
}
static void StartWithPath() {
Process.Start(TestPath);
}
static void StartWithInfo() {
var p = new Process { StartInfo = new ProcessStartInfo(TestPath) };
p.Start();
}
static void StartInNewThread() {
var t = new Thread(() => StartWithPath());
t.Start();
}
static string TestPath =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
"\\test.xlsx";
}
Calls to both StartWithPath and StartWithInfo block my thread in a console app. My console does not display "Process Started" until after the Excel splash screen closes and the main window is open.
StartInNewThread will display both messages on the console immediately, while the splash screen for Excel is still open.
We had this problem when launching a .bat script that was on a network drive on a different domain (we have dual trusted domains). I ran a remote C# debugger and sure enough Process.Start() was blocking indefinitely.
When repeating this task interactively in power shell, a security dialog was popping up:
As far as a solution, this was the direction we went. The person that did the work modified domain GPO to accomplish the trust.
Start server via command prompt:
"C:\Program Files (x86)\IIS Express\iisexpress" /path:\Publish /port:8080
This take access to sub-threads of the tree process of OS.
If you want to launch process and then make the process independent on the "launcher" / the originating call:
//Calling process
using (System.Diagnostics.Process ps = new System.Diagnostics.Process())
{
try
{
ps.StartInfo.WorkingDirectory = #"C:\Apps";
ps.StartInfo.FileName = #"C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE"; //command
ps.StartInfo.Arguments = #"C:\Apps\xyz.accdb"; //argument
ps.StartInfo.UseShellExecute = false;
ps.StartInfo.RedirectStandardOutput = false;
ps.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized;
ps.StartInfo.CreateNoWindow = false; //display a windows
ps.Start();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("==> Process error <=={0}" + ex.ToString(), Environment.NewLine));
}
}

Categories

Resources