บริการ windows จะรีสตาร์ทตัวเองโดยทางโปรแกรมได้อย่างไร?


135

ฉันต้องเขียนโค้ดที่มีประสิทธิภาพใน. NET เพื่อเปิดใช้งานบริการ windows (เซิร์ฟเวอร์ 2003) เพื่อรีสตาร์ทตัวเอง วิธีที่ดีที่สุดคืออะไร? มี. NET API ให้ทำบ้างไหม


7
"Robust" เป็นคำพังพอน ( stackoverflow.fogbugz.com/default.asp?W13086 ) - ลักษณะเฉพาะที่คุณต้องการคืออะไร?
Aidan Ryan

คำตอบ:


189

ตั้งค่าบริการให้รีสตาร์ทหลังจากความล้มเหลว (ดับเบิลคลิกที่บริการในแผงควบคุมและดูรอบ ๆ แท็บเหล่านั้น - ฉันลืมชื่อของมัน) จากนั้นเมื่อใดก็ตามที่คุณต้องการให้บริการเริ่มต้นใหม่เพียงโทรEnvironment.Exit(1)(หรือการส่งคืนที่ไม่ใช่ศูนย์) จากนั้นระบบปฏิบัติการจะรีสตาร์ทให้คุณ


7
Fyi ตำแหน่งอยู่ในแผงบริการคลิกขวาที่บริการที่ต้องการและเลือกคุณสมบัติจากนั้นเลือกแท็บการกู้คืน
James Michael Hare

20
ฉันเห็นว่าสิ่งนี้ทำให้เกิดพฤติกรรมที่ต้องการได้อย่างไร แต่รหัสส่งคืนเป็น 1 มีไว้เพื่อบอกระบบว่ามีข้อผิดพลาด นี่ไม่ใช่แนวทางปฏิบัติที่ไม่ดีหากไม่มีข้อผิดพลาดและคุณแค่ต้องการเริ่มบริการใหม่
mgttlinger

4
สิ่งนี้สามารถทำได้โดยโปรแกรมติดตั้งบริการในเหตุการณ์หลังการติดตั้งไม่จำเป็นต้องคลิกรอบ ๆ ... จะเป็นอย่างไรหากบริการของคุณอยู่บนเซิร์ฟเวอร์ระยะไกลและคุณต้องติดตั้งหลายครั้งต่อวันเช่นระหว่างการทดสอบ
Dean Kuga

5
@mgttlinger: ฉันคิดว่าใช่เป็นการปฏิบัติที่ไม่ดีเมื่อบริการของคุณมีสุขภาพดีดังนั้นจึงไม่จำเป็นต้องเริ่มต้นใหม่ แต่สถาปัตยกรรมบริการบางอย่างไม่สามารถเข้าถึงได้และหากจำเป็นต้องเริ่มต้นใหม่เป็นอาการที่แสดงว่าไม่ดีดังนั้นไม่มีปัญหาในการปิดและปลดปล่อย resorces ขั้นต่ำบางส่วน (ถ้าเป็นไปได้) และ 'ตัดเท้า' ตั้งแต่ออกจาก บริการที่ทำงานไม่ถูกต้องอาจแย่ลง (ไร้ประโยชน์)
Luciano

5
@JohnLeidegren หากคุณต้องการปิดระบบที่เหมาะสมคุณสามารถตั้งค่าService.ExitCode = 1และดำเนินการService.Stop()พร้อมกับการเปิดใช้งานช่องทำเครื่องหมาย "เปิดใช้งานการดำเนินการเพื่อหยุดด้วยข้อผิดพลาด" บนหน้าจอการตั้งค่าการกู้คืนบริการ การทำเช่นนี้จะช่วยให้สามารถปิดเครื่องได้อย่างเหมาะสมและยังคงเริ่มการทำงาน
Chris Rice

22
Dim proc As New Process()
Dim psi As New ProcessStartInfo()

psi.CreateNoWindow = True
psi.FileName = "cmd.exe"
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE"
psi.LoadUserProfile = False
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Hidden
proc.StartInfo = psi
proc.Start()

3
อย่าลืมเพิ่ม "" ล้อมรอบชื่อบริการของคุณหากมีช่องว่าง
apc

4
นี่เป็นเพียงบริการที่ทำงานภายใต้บัญชีที่มีสิทธิพิเศษเท่านั้นซึ่งเป็นความคิดที่ไม่ดี
Dmitry Gusarov

ขึ้นอยู่กับสภาพแวดล้อมของคุณคุณอาจต้องตรวจสอบให้แน่ใจว่ากระบวนการ cmd.exe ทำงานในกลุ่มกระบวนการที่แยกจากกัน ฉันพยายามใช้สิ่งนี้ แต่กระบวนการลูก cmd.exe เสียชีวิตทุกครั้งที่มีการดำเนินการ "net stop" เพื่อหลีกเลี่ยงปัญหานี้คุณต้องเรียก CreateProcess โดยระบุ CREATE_NEW_PROCESS_GROUP
Joppe

17

คุณไม่สามารถแน่ใจได้ว่าบัญชีผู้ใช้ที่บริการของคุณกำลังทำงานอยู่แม้จะมีสิทธิ์หยุดและเริ่มบริการใหม่


แม้ว่า +1-ed ในขณะที่ฉันประสบปัญหาเดียวกันเมื่อดูที่ sc.exe ปรากฎว่าใช้ SERVICE_QUERY_CONFIG เป็น dwDesiredAccess เมื่อเรียก OpenSCManager () จากนั้นเรียก OpenService () ด้วย SERVICE_START | SERVICE_STOP เพื่อเปิดบริการเฉพาะและใช้งานได้ดี (ไม่มีปัญหาในการเข้าถึง) ไม่แน่ใจว่าจะทำได้อย่างไรใน. NET
n0p

Windows Services ส่วนใหญ่จะทำงานเป็นระบบดังนั้นจึงไม่น่ามีปัญหา
เปลี่ยน

@Switch มีบริการมากมายที่ทำงานภายใต้ NETWORK SERVICE ซึ่งโดยค่าเริ่มต้นจะไม่มีสิทธิ์เปิดไฟล์ปฏิบัติการของตัวเอง
AgentFire

@AgentFire ถูกต้อง แต่ค่าเริ่มต้นคือ Local System ไม่ใช่ NETWORK SERVICE ระบบโลคัลมีสิทธิ์ในระดับสูงสุดสำหรับระบบปฏิบัติการ - เกินกว่าที่กำหนดให้กับสมาชิกของกลุ่มผู้ดูแลระบบภายใน
เปลี่ยน

@Switch แต่การใช้สิทธิ์ของผู้ใช้ได้มากที่สุดคือการละเมิดPol-หลักการ
AgentFire

12

คุณสามารถสร้างกระบวนการที่เป็นพรอมต์คำสั่ง DOS ที่รีสตาร์ทตัวเอง:

 Process process = new Process();
 process.StartInfo.FileName = "cmd";
 process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
 process.Start();

สิ่งนี้จะสืบทอดบริบทความปลอดภัยของเธรดการโทร ... และตราบใดที่บริบทนั้นมีแรงม้าเพียงพอที่จะรีสตาร์ทคุณก็ทำได้ดี
Clay

12
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);

ที่ไหน SERVICENAMEชื่อบริการของคุณ (เครื่องหมายอัญประกาศคู่รวมอยู่ในช่องว่างในชื่อบริการสามารถละเว้นได้)

ทำความสะอาดไม่จำเป็นต้องกำหนดค่าการรีสตาร์ทอัตโนมัติ


9
ได้เรียนรู้สิ่งใหม่ ๆ เกี่ยวกับ & vs &&: [command1] & [command2] จะรันคำสั่งทั้งสองตามลำดับเสมอในขณะที่ [command1] && [command2] รัน command2 ก็ต่อเมื่อ command1 ทำงานสำเร็จ ( autoitscript.com/forum/topic/… )
เจฟฟรีย์ Knight

5

ขึ้นอยู่กับว่าทำไมคุณถึงต้องการให้รีสตาร์ทตัวเอง

หากคุณกำลังมองหาวิธีที่จะให้บริการทำความสะอาดตัวเองเป็นระยะ ๆ คุณอาจมีตัวจับเวลาที่ทำงานในบริการซึ่งทำให้เกิดการล้างตามปกติเป็นระยะ ๆ

หากคุณกำลังมองหาวิธีเริ่มต้นใหม่เมื่อเกิดความล้มเหลว - โฮสต์บริการเองสามารถให้ความสามารถนั้นได้เมื่อมีการตั้งค่า

แล้วทำไมคุณต้องรีสตาร์ทเซิร์ฟเวอร์? คุณพยายามทำอะไรให้สำเร็จ?


1
สิ่งนี้จะไม่ได้ผลหากคุณกังวลกับ Large Object Heap และการกระจายตัวของหน่วยความจำ สมมติว่ากระบวนการ. NET 4 / 4.5 และ 64 บิตช่วยได้มากในเรื่องนี้
David Kassa

3

ฉันไม่คิดว่าคุณจะสามารถใช้บริการในตัวได้ (เมื่อคุณเรียกรีสตาร์ทระบบจะหยุดบริการซึ่งจะขัดจังหวะคำสั่งรีสตาร์ทและจะไม่เริ่มต้นอีกเลย) หากคุณสามารถเพิ่ม. exe ตัวที่สอง (แอปคอนโซลที่ใช้คลาส ServiceManager) คุณสามารถเริ่มต้น. exe แบบสแตนด์อโลนและรีสตาร์ทบริการจากนั้นออก

ในความคิดที่สองคุณอาจให้บริการลงทะเบียนงานตามกำหนดเวลา (เช่นใช้คำสั่งบรรทัดคำสั่ง 'at') เพื่อเริ่มบริการจากนั้นให้หยุดทำงานเอง นั่นอาจจะใช้ได้


3

ปัญหาในการแบ่งออกเป็นแบตช์ไฟล์หรือ EXE คือบริการอาจมีหรือไม่มีสิทธิ์ที่จำเป็นในการเรียกใช้แอปภายนอก

วิธีที่สะอาดที่สุดที่ฉันพบคือใช้เมธอด OnStop () ซึ่งเป็นจุดเริ่มต้นสำหรับ Service Control Manager จากนั้นรหัสการล้างข้อมูลทั้งหมดของคุณจะทำงานและคุณจะไม่มีซ็อกเก็ตแขวนหรือกระบวนการอื่น ๆ โดยสมมติว่ารหัสหยุดของคุณทำงานได้ดี

ในการดำเนินการนี้คุณต้องตั้งค่าสถานะก่อนที่คุณจะยุติซึ่งจะบอกให้เมธอด OnStop ออกด้วยรหัสข้อผิดพลาด จากนั้น SCM จะรู้ว่าต้องเริ่มบริการใหม่ หากไม่มีการตั้งค่าสถานะนี้คุณจะไม่สามารถหยุดบริการด้วยตนเองจาก SCM ได้ นอกจากนี้ยังถือว่าคุณได้ตั้งค่าบริการเพื่อเริ่มต้นใหม่เมื่อเกิดข้อผิดพลาด

นี่คือรหัสหยุดของฉัน:

...

bool ABORT;

protected override void OnStop()
{
    Logger.log("Stopping service");
    WorkThreadRun = false;
    WorkThread.Join();
    Logger.stop();
    // if there was a problem, set an exit error code
    // so the service manager will restart this
    if(ABORT)Environment.Exit(1);
}

หากบริการเกิดปัญหาและจำเป็นต้องรีสตาร์ทฉันจะเปิดเธรดที่หยุดบริการจาก SCM สิ่งนี้ช่วยให้บริการสามารถล้างข้อมูลได้เอง:

...

if(NeedToRestart)
{
    ABORT = true;
    new Thread(RestartThread).Start();
}

void RestartThread()
{
    ServiceController sc = new ServiceController(ServiceName);
    try
    {
        sc.Stop();
    }
    catch (Exception) { }
}

2

ฉันจะใช้ Windows Scheduler เพื่อกำหนดเวลาการเริ่มบริการของคุณใหม่ ปัญหาคือคุณไม่สามารถเริ่มต้นใหม่ได้ แต่คุณสามารถหยุดตัวเองได้ (โดยพื้นฐานแล้วคุณได้เลื่อยกิ่งไม้ที่คุณกำลังนั่งอยู่ ... ถ้าคุณได้รับการเปรียบเทียบของฉัน) คุณต้องมีกระบวนการแยกต่างหากเพื่อทำเพื่อคุณ Windows Scheduler เป็นเครื่องมือที่เหมาะสม กำหนดเวลางานครั้งเดียวเพื่อเริ่มบริการของคุณใหม่ (แม้จากภายในบริการเอง) เพื่อดำเนินการทันที

มิฉะนั้นคุณจะต้องสร้างกระบวนการ "ต้อน" ที่ทำเพื่อคุณ


2

คำตอบแรกสำหรับคำถามเป็นวิธีแก้ปัญหาที่ง่ายที่สุด: "Environment.Exit (1)" ฉันใช้สิ่งนี้บน Windows Server 2008 R2 และทำงานได้อย่างสมบูรณ์ บริการจะหยุดเอง O / S รอ 1 นาทีจากนั้นรีสตาร์ท


รอนานแค่ไหนขึ้นอยู่กับว่าคุณตั้งค่าให้รอนานแค่ไหน ค่าเริ่มต้นคือ 1 นาที แต่ถ้ามีคนไม่ต้องการคำตอบของคุณจะให้การแสดงผลผิด
Espen

1

ฉันไม่คิดว่ามันจะทำได้ เมื่อบริการ "หยุด" บริการจะถูกยกเลิกการโหลดทั้งหมด

โอเคฉันคิดว่ามีวิธีเสมอ ตัวอย่างเช่นคุณสามารถสร้างกระบวนการแยกเพื่อหยุดบริการจากนั้นเริ่มต้นใหม่จากนั้นออก


0

แนวทางที่ดีกว่าคือการใช้ NT Service เป็นเครื่องห่อสำหรับแอปพลิเคชันของคุณ เมื่อเริ่มบริการ NT แอปพลิเคชันของคุณสามารถเริ่มต้นในโหมด "ไม่ได้ใช้งาน" เพื่อรอให้คำสั่งเริ่มทำงาน (หรือได้รับการกำหนดค่าให้เริ่มโดยอัตโนมัติ)

ลองนึกถึงรถยนต์เมื่อสตาร์ทแล้วมันเริ่มอยู่ในสถานะว่างรอให้คำสั่งของคุณเดินหน้าหรือถอยหลัง นอกจากนี้ยังช่วยให้ได้รับประโยชน์อื่น ๆ เช่นการดูแลระบบระยะไกลที่ดีขึ้นเนื่องจากคุณสามารถเลือกวิธีเปิดเผยแอปพลิเคชันของคุณได้


0

เพิ่งผ่าน: และคิดว่าฉันจะเพิ่มข้อมูลพิเศษ ...

นอกจากนี้คุณยังสามารถทิ้งข้อยกเว้นซึ่งจะปิดบริการ windows โดยอัตโนมัติและตัวเลือกการเริ่มต้นใหม่อัตโนมัติก็เริ่มต้นขึ้นปัญหาเดียวของสิ่งนี้คือหากคุณมีสภาพแวดล้อมการพัฒนาบนพีซีของคุณ JIT จะพยายามเตะเข้า และคุณจะได้รับข้อความแจ้งว่า debug Y / N บอกว่าไม่แล้วมันจะปิดแล้วเริ่มใหม่อย่างถูกต้อง (บนพีซีที่ไม่มี JIT มันใช้งานได้ทั้งหมด) เหตุผลที่ฉันหลอกคือ JIT นี้เป็นของใหม่สำหรับ Win 7 (เคยทำงานได้ดีกับ XP ฯลฯ ) และฉันกำลังพยายามหาวิธีปิดการใช้งาน JIT ... ฉันอาจลองใช้ Environment วิธีการออกที่กล่าวถึงที่นี่ดูว่า ที่ได้ผลเช่นกัน

Kristian: Bristol, สหราชอาณาจักร


3
ข้อยกเว้นการโยนทั้งหมดทางออก (1) ทั้งหมดนี้หลีกเลี่ยงการล้างแอปพลิเคชันอย่างเหมาะสม การออกอย่างไม่สง่างามเป็นวิธีแก้ปัญหาที่ไม่ดี
devshorts

0

สร้างไฟล์ restart.bat แบบนี้

@echo on
set once="C:\Program Files\MyService\once.bat"
set taskname=Restart_MyService
set service=MyService
echo rem %time% >%once%
echo net stop %service% >>%once%
echo net start %service% >>%once%
echo del %once% >>%once%

schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z
schtasks /run /tn %taskname%

จากนั้นลบงาน% taskname% เมื่อ% service% ของคุณเริ่มทำงาน


0

สร้าง appdomain แยกต่างหากเพื่อโฮสต์รหัสแอปพลิเคชัน เมื่อต้องรีสตาร์ทเราสามารถยกเลิกการโหลดและโหลด appdomain ใหม่แทนกระบวนการ (บริการ windows) นี่คือวิธีการทำงานของพูลแอพ IIS พวกเขาไม่ได้เรียกใช้แอพ asp.net โดยตรงพวกเขาใช้ appdmain แยกต่างหาก


-2

วิธีที่ง่ายที่สุดคือการมีไฟล์แบตช์ที่มี:

เริ่มต้นสุทธิหยุดสุทธิ

และเพิ่มไฟล์ลงในตัวกำหนดตารางเวลาด้วยช่วงเวลาที่คุณต้องการ


ไม่ทำงานเนื่องจากแบตช์หยุดระหว่างทั้งสองคำสั่งเนื่องจากเป็นกระบวนการย่อยของบริการเอง
Orabîg

-3
private static void  RestartService(string serviceName)
    {
        using (var controller = new ServiceController(serviceName))
        {
            controller.Stop();
            int counter = 0;
            while (controller.Status != ServiceControllerStatus.Stopped)
            {
                Thread.Sleep(100);
                controller.Refresh();
                counter++;
                if (counter > 1000)
                {
                    throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName));
                }
            }

            controller.Start();
        }
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.