Restart programu z opóźnieniem

0

Mam program który restartuje się co noc o określonej porze. Program ma też zabezpieczenie przed uruchomieniem więcej niż jednej instancji.
Zabezpieczenie realizuje poprzez wykorzystanie mutex-a, prosta sprawa.
Restart znowu realizuję poprzez WinAPI:

  Application.Terminate;
  ShellExecute(Handle, 'Open', PChar(Application.ExeName), nil, nil, SW_NORMAL);

czyli jeszcze prościej niż poprzednia właściwość.
Wszystko działało dłużej niż rok bez żadnych problemów. Niestety, serwer na którym jest program uruchomiony jest dość niemrawy (delikatnie mówiąc) a system dyskowy to katastrofa. Aktualizacje jeszcze go przymuliły. Są na szczęście rozmowy o upgrade dysków i zapewne moje problemy się zakończą. Co jednak nie oznacza że powinienem przejść do porządku dziennego nad problemem jaki wystąpił.

Dokładnie to wygląda tak:

  1. program się zamyka,
  2. program jest ponownie uruchamiany,
  3. sprawdzany jest warunek czy przypadkiem nie ma już uruchomionego takiego programu.

No i ze względu na powolność systemu dyskowego, system operacyjny w momencie startu aplikacji nadal uważa że poprzednia instancja nadal jest uruchomiona i to wszystko.

Pytanie, jak wprowadzić zwłokę po Application.Terminate a przed funkcją winapi?
Czy wystarczy jakiś timer, lub cokolwiek do obliczania czasu? Czy to jeszcze będzie działało po Application.Terminate?

3

AFAIR Windows posiada specjalne API do robienia czegoś już po zamknięciu się danego programu. Przykładem jest samousuwanie się pliku wykonywalnego. Rozglądnij się za czymś takim, bo najpewniej istnieje możliwość wykorzystania systemowego API do wygodnego restartu programu.

Edit: funkcja RegisterApplicationRestart wygląda obiecująco.

0

Jakby jednak RegisterApplicationRestart się nie sprawdziło (tak jak u mnie) to jest inne rozwiązanie:

  1. Gdy chcesz zrestartować program tworzysz w katalogu tymczasowym (tam gdzie masz prawa zapisu) skrypt .CMD który:
    a. kopiuje Twojego EXEka (np do *.BAK, czy do katalogu gdzie masz prawa zapisu),
    b. usuwa EXEka,
    c. jeśli plik dalej istnieje to wraca do punktu b,
    d. (tu EXE nie istnieje, czyli na 100% jest zamknięty) przywracasz EXEka na miejsce,
    e. skrypt usuwa sam siebie.
  2. Uruchamiasz ten skrypt.
  3. Spokojnie zamykasz program.

Aby odciążyć zapętlenie można wrzucić polecenie "timeout 1".

Jeśli EXEk jest duży i operacja robi się upierdliwa to możesz to robić z jakimś statycznie ładowanym DLLem (o ile używa go tylko ten EXE).

Wiem że rozwiązanie technicznie nijakie ale działa u mnie przy aktualizacji programów od lat, na wielu systemach (od Win2k) i niezależnie od uprawnień użytkownika.

2

Nie możesz przed restartem po prostu przez CloseHandle zamknąć utworzonego muteksa? To powinno zadziałać a najmniej przerabiania.

0

@kAzek: o zerknę, ciekawy pomysł

1

Tyle samo przerabiania jest w przypadku API systemowego — wymieniasz linijkę z ShellExecute na RegisterApplicationRestart i to tyle. @robertz68 — nie wiem dlaczego się bronisz przed czymś, co zostało właśnie do tego celu zaprojektowane i istnieje w systemie od WinVista. Potrzebujesz wsparcia na jeszcze starszych systemach?

0

@furious programming: kompletnie nie interesują mnie starsze systemy operacyjne :)
A twoja sugestia jest dużo lepsza niż mi się na początku wydawało. W zasadzie to szukałem kiedyś takiego rozwiązania i na pewno z niego skorzystam.
Mój podstawowy klient pracuje w "ruchu ciągłym" i od zawsze miałem pewne problemy z aplikacjami które w ten właśnie sposób muszą działać. Szczególnie jest to trudne do utrzymania gdy aplikacje dodatkowo muszą pobierać dane przez sieć (czy to wewnętrzną czy też z Internetu). Jednak już wtedy nie wszystko zależy ode mnie.
Dlatego rozwiązanie resetujące aplikację gdy napotka błąd to jest dobre rozwiązanie.

0

Z podaną przeze mnie funkcją jest taki plus, że nieważne jak długo aplikacja się wyłącza, system na nią poczeka i na pewno ją uruchomi ponownie — o ile rejestracja restartu przebiegnie pomyślnie, dlatego pasuje sprawdzić co ta funkcja zwróci i odpowiednio zareagować na kod błędu. Sam bym nie kombinował z batami — to już nie te czasu. Tylko dokładnie przeczytaj dokumentację, tak aby wszystko na jej temat wiedzieć.

Ta funkcja jest idealna do wszelkiego rodzaju aplikacji samoaktualizujących się, ze względu na możliwość podania parametrów linii poleceń. Najpewniej właśnie do tego celu została zaprojektowana.

2
robertz68 napisał(a):

Mój podstawowy klient pracuje w "ruchu ciągłym" i od zawsze miałem pewne problemy z aplikacjami które w ten właśnie sposób muszą działać. Szczególnie jest to trudne do utrzymania gdy aplikacje dodatkowo muszą pobierać dane przez sieć (czy to wewnętrzną czy też z Internetu). Jednak już wtedy nie wszystko zależy ode mnie.

Kłóciłbym się. To co chcesz zrobić to tylko owijanie problemu w sreberko i udawanie, że to złoto, nie mniej jednak kupa po jakimś czasie się rozleje ;) Takie coś tylko zatuszuje problem który może przy zwiększeniu wykorzystania aplikacji się pojawić ze zdwojoną siłą. Wtedy będziesz restartować aplikację co 12h? Nie sądzę ponieważ dojdziesz w końcu do ściany której nie przebijesz.

robertz68 napisał(a):

Dlatego rozwiązanie resetujące aplikację gdy napotka błąd to jest dobre rozwiązanie.

Jeszcze zależy co to za aplikacja. Jednak to takich celów (restart apki codziennie o północy) osobiście użyłbym harmonogramu zadań. Może on zabić aplikację oraz uruchomić od nowa.

0

Czekajcie, to program ma się restartować, gdy napotka na błąd? Sądziłem, że o jakiś update chodzi. :D

0

Tak, o ile ja zrozumiałem to kolega chce aby program restartował się raz dziennie o określonej porze (zapewne w nocy). Do tego bym użył harmonogramu zadań. Jednak w trakcie wyszło, że po długim czasie bez restartu pojawiają się błędy (nie wiadomo jakie, ale jakieś są) i najprostszym rozwiązaniem jest restart :)

1

A no to w takim razie… nadal można bez problemu użyć RegisterApplicationRestart do tego celu. ;)

Ale to fakt, jeśli program sypie błędami i powoli staje się niestabilny, to pasuje znaleźć błędy i je naprawić.

0

Już koledzy tłumaczę, po pierwsze nie przesadzał bym z błędami, aplikacja to po prostu klient ftp plus parsowanie tego co pobierze i aktualizacja danych w Subiekcie GT.
Niestety, zdarza się (rzadko ale jednak) że coś nie pójdzie z pobieraniem danych przez protokół ftp, a to brak połączenia, a to Internet spowolni do szybkości starej Nokii, a to Windows dojdzie do wniosku że pora się zaktualizować no i czasami prąd może się skończyć. Przypadków może być dużo a niestety komputery należą do klientów i nie wszystko jest wzorowo.
Oczywiście, można się zabezpieczać, ale po roku, dwóch lub więcej nagle dowiaduję się że czegoś nie oprogramowałem. Ostatnio, po ładnych kilku latach okazało się że w trakcie parsowania nie zabezpieczyłem się przed pustym plikiem. W ogóle to nie miałem pojęcia że aplikacje klienckie mogą jakoś wysłać pusty plik?
Wiem, napiszecie, trzeba było to przewidzieć i macie rację. Ale ja specjalizuje się w pisaniu prostych aplikacji łączących dane z różnych systemów i zazwyczaj robię to prawie na kolanie. Taka specyfikacja. Nienawidzę tego ale z czegoś trzeba żyć a mam na to klientów.

Dlatego, w tym przypadku, jeśli coś pójdzie nie tak w trakcie pobierania danych (dzieje się to około 23.00 i powinno trwać około 5 minut), najłatwiej jest mi zrestartować program o pierwszej w nocy i zostawić pobieranie danych na następny dzień.
O dziwo działa to naprawdę dobrze, gdyby nie dysk wolny jak kulawy żółw to system pracował by zapewne następne kilka lat całkiem bezobsługowo.

Jak pisałem, dysk zostanie wymieniony na ssd i mój problem się skończy ale temat i tak uważam za ciekawy, może się jednak komuś przydać procedura restartu aplikacji po napotkaniu błędu.

0

Ale to i tak jest niezbyt eleganckie działanie programu :) Jak dla mnie wysypywanie się systemu jest dość przykre. Sam nie raz działając na programach ze stajni Embarcadero musiałem restartować IDE bo się albo zawiesiło, albo po długim czasie bez ponownego uruchamiania przestawało działać np. podpowiadanie składni czy w ekstremalnych przypadkach kompilacja kończyła się błędem (tego już w ogóle nie jestem w stanie pojąć). Po restarcie środowiska ten sam projekt kompilował się bez zająknięcia.

A co do problemu, to możesz jeszcze przed uruchomieniem problematycznej funkcji uruchomić coś w stylu watchdoga. Mały programik który sprawdza stan Twojego programu i w razie czego ubija go i restartuje od nowa.

0

Proponuję utworzyć aplikację sprawdzającą i zarządzającą procesem bo moim zdaniem Twój kod to za mało.:

 Application.Terminate;
  ShellExecute(Handle, 'Open', PChar(Application.ExeName), nil, nil, SW_NORMAL);

Przypatrz się wirusom, a zobaczysz jak powstaje zawsze uruchomienie aplikacji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1