I have create a windows service in VS 2010. I install it and also run it at the same time and set startup type to Automatic . I see it running fine through EventViewer and is successfully completed.
But after that i done see EventViewer showing anything, even if the work is doen it still should check DB and skip as all rows done.
So what is the issue ?
DO i need to make it an infinite loop in the service to keep it running?
Something like
While (ROWs in DB ! = null) ?
Because it does not seem it is working like task scheduler!
Yes, you need to do a loop with the possibility to break it again. Example service (VB.NET):
Public Class MyService
Protected Property IsRunning As Boolean = False
Protected Sub OnStart(args() As String)
IsRunning = True
' make the loop function run asynchronously
Dim t As New System.Threading.Thread(AddressOf MyLoopFunction)
t.Start()
End Sub
Protected Sub MyLoopFunction
While IsRunning
' here comes your code ...
' sleep for a second for better CPU freedom
System.Threading.Thread.Sleep(1000)
End While
End Sub
Protected Sub OnStop()
IsRunning = False
End Sub
End Class
Related
I'm writing the following module to capture SIGTERM that gets occasionally sent to my Delayed Job workers, and sets a variable called term_now that lets my job gracefully terminate itself before it's complete.
The following code in my module works perfect if I put it inline in my job, but I need it for several jobs and when I put it in a module it doesn't work.
I assume it's not working because it only passes term_now one time (when it's false), and even when it returns true it doesn't pass it again, therefore it never stops the job.
module StopJobGracefully
def self.execute(&block)
begin
term_now = false
old_term_handler = trap('TERM') do
term_now = true
old_term_handler.call
end
yield(term_now)
ensure
trap('TERM', old_term_handler)
end
end
end
Here's the working inline code how it's normally used (this is the code I'm trying to convert to a module):
class SMSRentDueSoonJob
def perform
begin
term_now = false
old_term_handler = trap('TERM') do
term_now = true
old_term_handler.call
end
User.find_in_batches(batch_size: 1000) do
if term_now
raise 'Gracefully terminating job early...'
end
# do lots of complicated work here
end
ensure
trap('TERM', old_term_handler)
end
end
end
you basically answered it yourself. in the example code you provided, term_now will only become true when the trap snapped before yield is called.
what you need to do is provide a mechanism that periodically fetches the information, so that you can check within the runs of ie find_in_batches.
so instead of yielding the result, your module should have a term_now method that might return an instance variable #term_now.
I'm seeing some strange behavior in a spock test for a service using Grails 2.3.7.
This test works fine:
void "create spot order"() {
given:
def createOrderCommand = newCreateOrderCommand(OrderType.S)
when:
def orderId = service.createOrder(createOrderCommand, user).id.toInteger()
then:
Order.count() == 1
when:
def order = service.orderById(orderId)
then:
// a bunch of assertions
}
This test also works fine:
void "create command with invalid order id"() {
when:
service.commandForOrderId(999)
then:
def exception = thrown(CreateOrderException)
exception.key == "orderService.invalid.order.id"
}
However this test fails - I've set a breakpoint at the beginning commandForOrderId, and it is never hit. command is null (this is where the test fails, on the line checking for null on command), which would never be returned from this service method:
void "create spot command"() {
given:
def createOrderCommand = newCreateOrderCommand(OrderType.S)
when:
def order = service.createOrder(createOrderCommand, user)
then:
Order.count() == 1
when:
def orderId = order.id.toInteger()
def command = service.commandForOrderId(orderId)
then:
command
// a bunch more assertions
}
I've tried removing the #Transactional annotation from the service, using the transactional static field, as well as using neither of these. I've also tried changing the service method to a closure, all with no luck.
I changed the service method to a closure, cleared my target directories, did every manner of clean I know of (within GGTS and grails commands), and the service method started getting hit in the test. I'm still unsure of the actual cause of this error, however.
I have some code that potentially can run for a longer period of time. However if it does I want to kill it, here is what I'm doing at the moment :
def perform
Timeout.timeout(ENV['JOB_TIMEOUT'].to_i, Exceptions::WorkerTimeout) { do_perform }
end
private
def do_perform
...some code...
end
Where JOB_TIMEOUT is an environment variable with value such as 10.seconds. I've got reports that this still doesn't prevent my job from running longer that it should.
Is there a better way to do this?
I believe delayed_job does some exception handling voodoo with multiple retries etc, not to mention that I think do_perform will return immediately and the job will continue as usual in another thread. I would imagine a better approach is doing flow control inside the worker
def perform
# A nil timeout will continue with no timeout, protect against unset ENV
timeout = (ENV['JOB_TIMEOUT'] || 10).to_i
do_stuff
begin
Timeout.timeout(timeout) { do_long_running_stuff }
rescue Timeout::Error
clean_up_after_self
notify_business_logic_of_failure
end
end
This will work. Added benefits are not coupling delayed_job so tightly with your business logic - this code can be ported to any other job queueing system unmodified.
I have a time consuming script, and I want to periodically log it execution time. How do I find out the current execution time?
The symfonian way to log execution times is using the timer manager that comes with symfony.
//Get timer instance called 'myTimer'.
$timer = sfTimerManager::getTimer('myTimer');
//Start timer.
$timer->startTimer();
// Do things
...
// Stop the timer and add the elapsed time
$timer->addTime();
This timer will be saved into any logger you have configured with your symfony.
By default symfony has the sfWebDebugLogger for the DEV environment but you can create your own and configure it in the factories.yml file.
The nice thing about this logger is that it logs also the number of calls to the timer.
Why not use date('Y-m-d H:i:s') and log that... and/or calculate difference from a start time obtained with date() as well?
Think about what you are asking, each action is logged in symfony log (root/log/app_name_[env].log). This logging is done once the operation has ended, (there is no easy way to figure out the execution time of a thread executing a php from php). You could try messing up with code and add code in order to log at certain points of the code, the current execution time, something like:
$init = microtime();
log("Process started at:". $init);
foreach($this->getLotsOfRecords() as $index=>$record)
{
$start = microtime();
log ($index." record started at".microtime());
[do stuff]
$end = microtime();
log ($index." record ended at". $end . " time elapsed: ". ($start - $end));
}
$last = microtime();
log("Total elapsed time is: ". ($init - $last));
This is pseudo code but i believe you can figure out the rest, hope this helps!
I ended up writing my own static class:
class Timer
{
protected static $start = null;
public static function getDuration($format = '%H:%I:%S')
{
$now = new DateTime();
if (!self::$start)
{
self::$start = new DateTime();
}
$period = $now->diff(self::$start);
return $period->format($format);
}
}
And logging it in partial (that is looped):
<?php $logger->log(sprintf("Duration: %s", $duration = Timer::getDuration())) ?>
I had an application which reads some data from a web database and updates the local database - on a periodic basis. Say every 5 mins.
This was in the form of an interactive windows application. But since this application has to run continuously, we decided to make a Windows Service Application.
We were using timers in the application, which were set to an interval of 5 mins, and in every tick of the timer, we were checking for the web updates.
We have carried the same thing in the service. But it seems the timers are not running now. Following are the few methods from the service:
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
'connect to sap business one
If Connect("rlap1", "sa", "dracula", "UnimaxNew", "manager", "manager") = False Then
End
SyncEvents.WriteEntry("Unable to connect to SAP Business One, " & oCompany.GetLastErrorDescription, EventLogEntryType.Error)
Else
SyncEvents.WriteEntry("Connected to SAP Business One.", EventLogEntryType.Information)
End If
'start the timers
WebTimer.Start()
SapTimer.Start()
DataTimer.Start()
SyncEvents.WriteEntry("Synchronization process started.")
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
oCompany.Disconnect()
SyncEvents.WriteEntry("Disconnected from SAP Business One.", EventLogEntryType.Information)
'stop the timers
WebTimer.Stop()
SapTimer.Stop()
DataTimer.Stop()
SyncEvents.WriteEntry("Synchronization process stopped.")
End Sub
Private Sub WebTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles WebTimer.Tick
SyncEvents.WriteEntry("Checking for new orders.")
CheckOrder()
End Sub
Private Sub SapTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SapTimer.Tick
SyncEvents.WriteEntry("Checking for new deliveries.")
CheckDelivery()
End Sub
Private Sub DataTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DataTimer.Tick
SyncEvents.WriteEntry("Checking for stock updates.")
CheckStock()
End Sub
The messages are log correctly in the event logs - when we start or stop the service. But there are no messages from timers function. Also I've tried debugging the service - by using Attach To Process.. in Visual Studio. But even than the code never breaked on any of the tick functions.
Can't we use the timers in the service? If no, than what is the other way. If yes, what could be wrong here?
Thanks
Rahul Jain
There's nothing that prevents timers from working in a Windows service. It sounds to me like the timer is not configured for auto-reset, but without knowing what timer you're using (System.Timers.Timer? System.Threading.Timer? Other?) and how it's configured, it's impossible to know for sure.
Regarding debugging the service, put the following code "programmatic breakpoint" in your OnStart() method:
System.Diagnostics.Debugger.Break();
When you start the service, you be prompted to enter a debug session, and the execution will break at this line. You can debug normally from there.