Bagaimana layanan windows secara terprogram restart sendiri?

Jawaban:

188

Atur layanan untuk memulai kembali setelah kegagalan (klik dua kali layanan di panel kontrol dan lihat-lihat tab tersebut - saya lupa namanya). Kemudian, kapan pun Anda ingin layanan dimulai ulang, cukup panggil Environment.Exit(1)(atau pengembalian bukan nol) dan OS akan memulai ulang untuk Anda.

TheSoftwareJedi
sumber
7
Untuk mengetahui lokasinya di panel layanan, klik kanan layanan yang dimaksud dan pilih properti, lalu pilih tab pemulihan.
James Michael Hare
20
Saya melihat bagaimana ini mencapai perilaku yang diinginkan tetapi kode kembali 1 dimaksudkan untuk memberi tahu sistem bahwa ada kesalahan. Bukankah ini praktik yang buruk jika ternyata tidak ada kesalahan dan Anda hanya ingin memulai ulang layanan Anda?
mgttlinger
4
Ini dapat dilakukan secara terprogram oleh penginstal layanan di acara setelah penginstalan, tidak perlu mengklik sekitar ... Bagaimana jika layanan Anda ada di server jarak jauh dan Anda perlu menginstalnya beberapa kali sehari, misalnya selama pengujian?
Dean Kuga
5
@mgttlinger: Saya pikir ya, adalah praktik yang buruk bila layanan Anda sehat, jadi tidak perlu dimulai ulang. Tetapi beberapa arsitektur layanan berada di luar jangkauan kami dan jika mereka perlu dimulai ulang adalah gejala bahwa itu tidak baik, jadi tidak ada masalah untuk menutup dan membebaskan beberapa resorsi minimum (jika mungkin) dan 'memotong kaki mereka', sejak meninggalkan layanan yang berjalan tidak semestinya bisa menjadi lebih buruk (tidak berguna).
Luciano
5
@JohnLeidegren jika Anda ingin mematikan dengan benar, Anda dapat mengatur Service.ExitCode = 1dan kemudian mengeksekusi Service.Stop()bersama dengan mengaktifkan kotak centang 'Aktifkan tindakan untuk berhenti dengan kesalahan` pada layar pengaturan pemulihan layanan. Melakukannya dengan cara ini memungkinkan pematian yang benar dan masih memicu mulai ulang.
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()
Khalid Rahaman
sumber
3
Ingatlah untuk menambahkan "" di sekitar nama layanan Anda jika berisi spasi.
apc
4
Ini hanya untuk layanan yang berjalan dengan akun dengan hak istimewa, yang bagaimanapun juga merupakan ide yang buruk.
Dmitry Gusarov
Bergantung pada lingkungan Anda, Anda mungkin harus memastikan bahwa proses cmd.exe berjalan dalam grup proses terpisah. Saya mencoba menerapkan ini, tetapi proses anak cmd.exe mati setiap kali "net stop" dijalankan. Untuk menghindari ini, Anda perlu memanggil CreateProcess dengan CREATE_NEW_PROCESS_GROUP ditentukan.
Joppe
17

Anda tidak dapat memastikan bahwa akun pengguna yang menjalankan layanan Anda bahkan memiliki izin untuk menghentikan dan memulai ulang layanan.

Greg Hewgill
sumber
Meskipun diberi +1 karena saya menghadapi masalah yang sama, ketika melihat sc.exe ternyata ia menggunakan SERVICE_QUERY_CONFIG sebagai dwDesiredAccess saat memanggil OpenSCManager () dan kemudian memanggil OpenService () dengan SERVICE_START | SERVICE_STOP untuk membuka layanan tertentu dan berfungsi dengan baik (tidak ada masalah dengan akses). Tidak yakin tentang bagaimana ini bisa dilakukan di .NET.
n0p
Sebagian besar Layanan Windows berjalan sebagai Sistem, jadi seharusnya tidak menjadi masalah.
Beralih
@Switch ada lingkaran besar layanan yang dijalankan di bawah NETWORK SERVICE, yang secara default bahkan tidak memiliki hak untuk membuka file yang dapat dieksekusi sendiri.
AgentFire
@AgentFire, benar, tetapi defaultnya adalah Sistem Lokal, bukan LAYANAN JARINGAN. Sistem Lokal secara inheren memiliki tingkat hak istimewa tertinggi untuk sistem operasi - melebihi yang diberikan kepada anggota grup Administrator lokal.
Beralih
@Switch tetapi menggunakan hak istimewa yang paling tersedia melanggar Prinsip-PoL .
AgentFire
12

Anda dapat membuat proses yang merupakan prompt perintah DOS yang dimulai ulang sendiri:

 Process process = new Process();
 process.StartInfo.FileName = "cmd";
 process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
 process.Start();
VladL
sumber
Ini, tanpa melakukan hal lain, akan mewarisi konteks keamanan dari utas panggilan ... dan selama itu konteks yang memiliki tenaga kuda yang cukup untuk memulai ulang, Anda baik-baik saja.
Clay
12
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);

di mana SERVICENAMEnama layanan Anda (tanda kutip ganda disertakan untuk memperhitungkan spasi dalam nama layanan, jika tidak dapat dihilangkan).

Bersih, tidak perlu konfigurasi restart otomatis.

Filip
sumber
9
mempelajari sesuatu yang baru tentang & vs &&: [command1] & [command2] akan selalu menjalankan kedua perintah secara berurutan, sedangkan [command1] && [command2] menjalankan perintah2 hanya jika command1 berhasil dijalankan ( autoitscript.com/forum/topic/… )
Jeffrey Knight
5

Itu akan tergantung pada mengapa Anda ingin me-restart sendiri.

Jika Anda hanya mencari cara agar layanan membersihkan dirinya sendiri secara berkala, maka Anda dapat memiliki pengatur waktu yang berjalan di layanan yang secara berkala menyebabkan rutinitas pembersihan.

Jika Anda mencari cara untuk memulai ulang saat gagal - host layanan itu sendiri dapat menyediakan kemampuan itu saat disiapkan.

Jadi mengapa Anda perlu me-restart server? Apa yang ingin Anda capai?

Brody
sumber
1
Ini tidak akan berfungsi jika Anda khawatir dengan Large Object Heap dan fragmentasi memori. Seharusnya proses .NET 4 / 4.5 dan 64-bit telah banyak membantu dalam hal ini.
David Kassa
3

Saya rasa Anda tidak dapat melakukannya dalam layanan mandiri (saat Anda memanggil Restart, itu akan menghentikan layanan, yang akan mengganggu perintah Restart, dan tidak akan pernah memulai lagi). Jika Anda dapat menambahkan .exe kedua (aplikasi Konsol yang menggunakan kelas ServiceManager), Anda dapat memulai .exe mandiri dan memintanya memulai ulang layanan, lalu keluar.

Setelah dipikir-pikir, Anda mungkin bisa meminta layanan mendaftarkan Tugas Terjadwal (menggunakan perintah baris perintah 'at', misalnya) untuk memulai layanan dan kemudian menghentikannya sendiri; itu mungkin akan berhasil.

teknofil
sumber
3

Masalah dengan mengupas ke file batch atau EXE adalah bahwa layanan mungkin memiliki atau tidak memiliki izin yang diperlukan untuk menjalankan aplikasi eksternal.

Cara terbersih untuk melakukan ini yang saya temukan adalah dengan menggunakan metode OnStop (), yang merupakan titik masuk untuk Service Control Manager. Kemudian semua kode pembersihan Anda akan berjalan, dan Anda tidak akan memiliki soket gantung atau proses lain, dengan asumsi kode penghentian Anda melakukan tugasnya.

Untuk melakukan ini, Anda perlu menyetel bendera sebelum Anda mengakhiri yang memberi tahu metode OnStop untuk keluar dengan kode kesalahan; maka SCM mengetahui bahwa layanan perlu direstart. Tanpa tanda ini, Anda tidak akan dapat menghentikan layanan secara manual dari SCM. Ini juga mengasumsikan Anda telah menyiapkan layanan untuk memulai ulang saat terjadi kesalahan.

Ini kode stop saya:

...

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);
}

Jika layanan mengalami masalah dan perlu dimulai ulang, saya meluncurkan utas yang menghentikan layanan dari SCM. Ini memungkinkan layanan untuk membersihkan dirinya sendiri:

...

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

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

Saya akan menggunakan Penjadwal Windows untuk menjadwalkan restart layanan Anda. Masalahnya adalah Anda tidak dapat memulai ulang diri sendiri, tetapi Anda dapat menghentikan diri sendiri. (Anda pada dasarnya telah memotong cabang yang Anda duduki ... jika Anda mendapatkan analogi saya) Anda memerlukan proses terpisah untuk melakukannya untuk Anda. Penjadwal Windows adalah salah satu yang sesuai. Jadwalkan tugas satu kali untuk memulai ulang layanan Anda (bahkan dari dalam layanan itu sendiri) agar segera dijalankan.

Jika tidak, Anda harus membuat proses "penggembalaan" yang melakukannya untuk Anda.

dviljoen.dll
sumber
2

Tanggapan pertama untuk pertanyaan tersebut adalah solusi paling sederhana: "Environment.Exit (1)" Saya menggunakan ini di Windows Server 2008 R2 dan bekerja dengan sempurna. Layanan berhenti sendiri, O / S menunggu 1 menit, lalu memulai ulang.

tangentMan
sumber
Berapa lama menunggu tergantung pada berapa lama Anda mengaturnya untuk menunggu. Defaultnya adalah 1 menit, tetapi jika seseorang tidak menginginkan jawaban Anda akan memberikan kesan yang salah.
Espen
1

Saya tidak berpikir itu bisa. Ketika sebuah layanan "dihentikan", itu akan dibongkar sepenuhnya.

Baiklah, selalu ada cara yang saya kira. Misalnya, Anda dapat membuat proses yang terlepas untuk menghentikan layanan, lalu memulai ulang, lalu keluar.

TED
sumber
0

Pendekatan yang lebih baik mungkin dengan memanfaatkan Layanan NT sebagai pembungkus untuk aplikasi Anda. Ketika Layanan NT dimulai, aplikasi Anda bisa mulai dalam mode "diam" menunggu perintah untuk memulai (atau dikonfigurasi untuk memulai secara otomatis).

Bayangkan sebuah mobil, ketika dihidupkan dimulai dalam keadaan diam, menunggu perintah Anda untuk maju atau mundur. Hal ini juga memungkinkan keuntungan lainnya, seperti administrasi jarak jauh yang lebih baik karena Anda dapat memilih cara mengekspos aplikasi Anda.

plamb
sumber
0

Hanya lewat: dan berpikir saya akan menambahkan beberapa info tambahan ...

Anda juga dapat memberikan pengecualian, ini akan menutup layanan windows secara otomatis, dan opsi re-start otomatis baru saja muncul. Satu-satunya masalah dengan ini adalah bahwa jika Anda memiliki lingkungan pengembang pada pc Anda maka JIT mencoba untuk masuk, dan Anda akan mendapatkan prompt yang mengatakan debug Y / N. katakan tidak, lalu tutup, lalu mulai ulang dengan benar. (pada PC tanpa JIT, semuanya berfungsi). alasan im trolling, apakah JIT ini baru untuk Win 7 (dulu berfungsi dengan baik dengan XP dll) dan saya mencoba menemukan cara untuk menonaktifkan JIT .... saya dapat mencoba metode Environment.Exit yang disebutkan di sini lihat caranya itu juga berhasil.

Kristian: Bristol, Inggris

Kristian
sumber
3
Semua pengecualian lemparan ini, keluar (1) solusi semua menghindari pembersihan aplikasi yang tepat.
Keluar dengan tidak
0

Buat file restart.bat seperti ini

@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%

Kemudian hapus tugas% taskname% saat% service% Anda dimulai

Erik Martino
sumber
0

Buat appdomain terpisah untuk menghosting kode aplikasi. Ketika membutuhkan restart, kita dapat membongkar dan memuat ulang appdomain sebagai gantinya (layanan windows). Ini adalah cara kerja pool aplikasi IIS, mereka tidak menjalankan aplikasi asp.net secara langsung, mereka menggunakan appdmain terpisah.

CreativeManix
sumber
-2

Cara termudah adalah memiliki file batch dengan:

bersih berhenti bersih mulai

dan tambahkan file ke penjadwal dengan interval waktu yang Anda inginkan


sumber
Ini tidak berfungsi karena batch dihentikan di antara kedua perintah, karena ini adalah proses turunan dari layanan itu sendiri.
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();
        }
    }
Lee Smith
sumber