[Ubuntu, .NET Core, Crontab] Uruchamiamy dotnet w Cronie

Moja potrzeba była dość prosta – uruchomić Serwer słuchający na określonym porcie protokołu TCP w Linuxie, serwer napisany było oczywiście w .NET Core.

Niezawodność

Jako podstawowy cel przyświecała mi niezawodność rozwiązania. Uchylając rąbka tajemnicy przed kolejnymi artykułami: aplikacja to „słuchacz komunikacji” przychodzącej z nadajników GPS. Oczywiście sama aplikacja napisana jest zgodnie z zasadą rozległej obsługi błędów, pełnego logowania zdarzeń (Nlog), restartowania serwera TCP w razie awarii itp., ale co w sytuacji gdy awarii ulegnie samo środowisko uruchomieniowe lub aplikacja po prostu „zawiesi się”?

W usługach Windows mamy do dyspozycji opcję samoczynnego restartowania usługi w razie awarii:

Services.msc opcje samoczynnego restartu usługi

W Linuxach też mamy wiele zaawansowanych metod wzajemnego monitorowania procesów, w wersji Enterprise pokusilibyśmy się o napisanie skryptu sięgającego do bazy logów i w razie potrzeby restartującego proces.

Uproszczenia

Ja poszedłem jednak nieco na skróty i wymyśliłem, że w tablicy CRONa dodam zadanie, które po prostu co godzinę – prewencyjnie będzie restartowało moją aplikację, nawet jeśli pkill trafi na czas gdy aplikacja przetwarza dane – nic poważnego się nie wydarzy, zaimplementowany mechanizm ponawiania po prostu powtórzy proces po restarcie.
Zdaje sobie sprawę, że nie jest to rozwiązanie eleganckie, ale jest przede wszystkim proste i działa spełniając wszystkie moje oczekiwania.

Cron i skrypt sh

Pamiętamy, że demon Crona ma tylko podstawowe ścieżki systemowe, nie mamy co liczyć, że będzie znał lokalizacje naszego dotnet’a, oczywiście możemy spróbować globalnie to uzdrowić, ale znów pytanie – po co i czy to na pewno zawsze zadziała… Zdecydowałem się więc na podanie pełnej ścieżki do dotnet’a w skrypcie i… działa idealnie! 🙂

Skrypt wygląda tak:

#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
pkill dotnet
cd /usr/dotnet/mydotnetapp/TK102publish
/usr/dotnet/dotnet TK102Btcp.dll

Jak widzicie najpierw ubijam proces dotnet’a, następnie nawiguje do folderu w którym mam binaria aplikacji – to bardzo ważne gdyż korzystam z plików konfiguracyjnych (m.in Nlog i config.json) dlatego mój folder uruchomieniowy musi zostać poprawnie zdefiniowany. 

Następnie zwyczajnie uruchamiam dotnet i wywołuję moją binarkę.

Wady

Oczywiście kilowanie procesu dotneta to nadużycie, w sytuacji gdyby na maszynie działało coś jeszcze – działanie tego czegoś również zostałoby przerwane, w przyszłości zapewne sięgnę po coś bardziej wyrafinowanego. W mojej sytuacji jednak w tym momencie jest to rozwiązanie wystarczające i sprawdza się wyśmienicie – mam pewność, że za każdym razem otrzymam świeżutką instancję dotneta – obojętnie coby się nie działo.

CRON

Ostatnim krokiem będzie uruchamianie mojego zadania co określony czas, w moim przypadku co godzinę. W razie katastrofalnego zbiegu wydarzę pozostanę bez odczytów GPS najwyżej godzinę, a wbudowany w moje urządzenia oraz serwer TCP mechanizm ponawiania sprawnie nadrobi tą lukę.

Edytujemy tablicę zadań zaplanowanych: crontab -e i dodajemy:

5 * * * * /usr/dotnet/mydotnetapp/Start.sh > /var/log/TK102.log 2>&1

Tutaj dodatkowo zapisuje w logach ostatnie informacje o uruchomieniu mojej aplikacji. Komenda 2>$1 przekierowuje standardowe wyjście błędów (2) na standardowe wyjście (1).

Na koniec restartujemy usługę Crona:

sudo service cron reload

I obserwujemy logi:

grep CRON /var/log/syslog

Troubleshooting

Jeśli skrypt sh nie chcę się uruchomić lub otrzymujecie dziwne komunikaty, a dodatkowo pisaliście go w edytorze uruchomionym na Widowsach możliwe że znalazły się w nim znaki (szczególnie końca linii), których Linux nie rozumie.

Dlatego skrypty pod Linuxa zalecam pisać w edytorach Linuxowych np. vim, nano, itp. lub ew. potraktować nasz skrypt tr’em lub w cięższych przypadkach  dos2unix’em.

tr -d "\r" < oldname.sh > newname.sh

lub

dos2unix -n file.txt output.txt

tr -d usunie znaki końca linii używane w Windowsie.
dos2unix zrobi to samo, ale dodatkowo  dokona konwersji z UTF-16 na UTF-8.

To tyle. Pozostaje nam cieszyć się działającym dotnetowym zadaniem zaplanowanym w Linuxie (kto by kiedyś pomyślał, że do tego dojdzie! 🙂 )

Leave a Reply