Building an application to do a task periodically on a server
I'm looking for some guidance on the overall architecture of this little system I'm building.
Currently, I have an app that is deployed (and updated) via xcopy to a few servers. This works 开发者_C百科well for updating the code, but it does not work well for updating the period of the code's execution, since it is setup as a windows scheduled task to run every hour. The xcopy replace works well, because I can run an update from my local machine, and push the new exe file to all the servers. And the next hour, the task scheduler will run the new exe.
I'd like to change it to work this way.
My app runs as a Windows Service and uses System.Threading.Timer to wait a given duration, and then execute the code. This way, part of the process could check the database and if necessary reduce the period of execution for a given server.
The issue there, is that since the .exe would be running as a service, it would not allow for easy updaing via xcopy since the file will be in use all the time.
Any thoughts on how I should set this up to be able to do easy xcopy updates, while running as a windows service? Is that even possible?
You can stop the service, then copy the files, then start the service from a batch file:
SET SOURCEDIR=\\coastappsdev\wwwroot\ClearTrac\Setup\03_Staging\ClearTracAutoSend\bin
SET SERVICE_HOME=C:\INETPUB\WWWROOT\ClearTracAutoSend
SET SERVICE_EXE=ClearTracAutoSend.exe
SET INSTALL_UTIL_HOME=C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
:STOP THE SERVICE:
SC \\targetServer STOP ClearTracAutoSend
:COPY THE FILES:
MD %SERVICE_HOME%
XCOPY %SOURCEDIR%\*.* %SERVICE_HOME%\*.* /E /R /Y
set PATH=%PATH%;%INSTALL_UTIL_HOME%
cd %SERVICE_HOME%
echo Uninstalling AutoSend Service...
installutil /u %SERVICE_EXE%
cd %SERVICE_HOME%
echo installing AutoSend Service...
installutil /i %SERVICE_EXE%
:START THE SERVICE:
SC \\targetServer ClearTracAutoSend
pause
This might not be the best solution for remote, I don't know how to run installutil remotely. We RDP to the server and run the batch file.
How about moving the updating code out of the service that simply checks the time for the next iteration into it's own assembly. Load that dynamically before each run and then unload it. I'm also wondering if Quartz.net is useful for you.
You could just have your Service Spawn a sub process(exe) and wait for that to exit.
This way your application could be updated easily because it is loaded, runs and then exits, and as long as you don't need to update your service it's all easy.
If want to be more tricky, you could set it up as an assembly(dll), that is either memory loaded via loading the dll into memory and then executing it, or you could setup a ShadowCopy directory that it runs from.
If you are open to stopping the service, pushing the code, and starting the service, you have a few options.
The best would be Powershell or MsBuild.
If you are concerned about timing, just set the service to run once when its started (or startTime + some interval) and then every hour.
If you really need this service to just stay running but be able to change the code between runs, you'll need something some the Managed Extensibility Framework (MEF) which allows the DLL code to be stored somewhere and loaded only during runtime, so it can be modified without a restart.
I ended up using a bit of @Decker97's solution, coupled with some powershell magic :)
function global:new-process()
{
param ([string]$computer, [string]$commandline=$(throw "Command line required."))
$path = "\\$computer\root\cimv2:Win32_Process"
$mc = new-object System.Management.ManagementClass $path
$cmdargs = $commandline,$null,$null,0
$ret = $mc.InvokeMethod("Create", $cmdargs)
if ($ret -eq 0) {
write-host "Created Process ID: $($cmdargs[3])"
}
else {
write-host "Error $ret creating process."
}
$mc.Dispose()
}
$serverNames = Get-Content C:\temp\servers.txt
foreach ($server in $serverNames)
{
write-host Updating $server
c:\windows\system32\sc.exe \\$server STOP Service
$source = "C:\Projects\Service\bin\Debug"
$dest = "\\" + $server + "\C$\Program Files\TargetFolder\TargetFolder"
ROBOCOPY.exe $source $dest /MIR /W:5 /R:1
new-process $server 'c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Installutil.exe /i /LogFile=install.out "C:\Program Files\TargetFolder\TargetFolder\serviceExecutable.exe"'
c:\windows\system32\sc.exe \\$server START Service
}
The script uses service control to try to stop the service.
Then it copies the files to the server with robocopy.
Then use WMI and Powershell to invoke "installutil" remotly on the server.
Then use service control to start up the service.
精彩评论