dotnet core - pisanie tzw. komend

1

W niektórych innych językach, popularne jest oferowanie przez wiodący framework tzw. komend, które na serwerze odpala np. cron według jakiegoś harmonogramu i stanowią uzupełnienie głównego projektu.

Różne frameworki adresują to na różny sposób, ale często dodając katalog /Commands/, w którym tworzy się klasy komend dziedziczące po pewnym interfejsie, a sam framework udostępnia wygodne narzędzia do parsowania argumentów, wyświetlania danych w cli etc. Wywołuje się je przez wspólny entry-point, np. bin/console nazwa:komendy.

Pogooglowałem trochę i nie widzę specjalnie analogii w świecie .Net. Najlepsze co mi przychodzi do głowy, to dołożyć projekt typu Console Application do solucji, podlinkować zasoby z innych projektów, sparsować args w funkcji Main, zrobić swoje i... tyle.

Tak to się robi wygodnie i profesjonalnie? :)

0
roSzi napisał(a):

Różne frameworki adresują to na różny sposób, ale często dodając katalog /Commands/, w którym tworzy się klasy komend dziedziczące po pewnym interfejsie, a sam framework udostępnia wygodne narzędzia do parsowania argumentów, wyświetlania danych w cli etc. Wywołuje się je przez wspólny entry-point, np. bin/console nazwa:komendy.

Jakie np?

4

Do prostych rzeczy możesz wykorzystać interfejs IHostedService lub jego prostą abstrakcyjną implementację BackgroundService. Taki serwis dodajesz w swoim startupie services.AddHostedService<TService>().

Do bardziej skomplikowanych rzeczy możesz wykorzystać jakąś bibliotekę, np. Quartz.NET.

0
roSzi napisał(a):

W niektórych innych językach, popularne jest oferowanie przez wiodący framework tzw. komend, które na serwerze odpala np. cron według jakiegoś harmonogramu i stanowią uzupełnienie głównego projektu.

...

Tak to się robi wygodnie i profesjonalnie? :)

Pytasz "nieco" mętnie, to ma zapach https://en.wikipedia.org/wiki/XY_problem
Ja poproszę o rozjaśnienie na takiej płaszczyźnie:

  • chcesz dodatkowych funkcjonalności "out of process" (samodzielny proces, myśl o tym jako "exe", w sumie kij kogo obchodzi w jakim języku)
  • czy "in process" (moduł programowy, w języku obiektowym w formie obiektowej)

jeśli przyzywany przez Ciebie "wiodący framework" (nie mam najmniejszego pojecia o czym mowa) potrzeby "in-proicess" realizuje "out-of-process", to pachnie jak zaszłość (bardzo) historyczna, albo nieporadność wyznaczających architekturę.

Wszystkie profesjonalne środowiska w nowoczesnych językach mają odpowiednik cron'a

Więc inaczej ujmując i wracajac do istoty: jaki cel chcesz zrealizować?

0

Dzięki za odpowiedzi. Nie chcę wywoływać żadnej dyskusji o wyższości X nad Y - załóżmy, że przywołane inne frameworki nie są wiodące, a języki przemilczmy :D.

Ale, for the record - komendy są w Django w Pythonie i w Symfony w PHP - to jednak narzędzia o innej filozofii więc uznałem, że w .net to się robi zupełnie inaczej. W nodejs robiłem do tego po prostu osobne pliki js na każdą z "komend".

Przepraszam też, że wypowiedziałem się nie jasno, na pewno mam wiele braków i nie jestem dobrze wykształconym, wszechstronnym programistą, a raczej (w miarę skutecznym) klepaczem :).

Posłużę się praktycznym przykładem:

  1. mamy spory monolit z webapi, core'em, może nawet frontendem (to akurat mało istotne),
  2. jednocześnie chcemy, by równolegle nasz monolit realizował zadania w tle - robił zapytanie na bazie i np. wysyłał powiadomienia mailowe odpowiednim osobom, które zwróciło zapytanie,
  3. jednocześnie chcemy, by można było manualnie odpalić jakieś zadanie z linii poleceń, np. import rekordów z innego systemu. Chcemy mieć też możliwość dodać takie zadanie do crona.

No i na przykład w Symfony (PHP) tworzy się na to tak zwane (to tylko nazwa, wszystko sprowadza się do procesu) Commandy, które opierają się o pewną konwencję. Dla powyższego przykładu stworzymy:
pkt. 2: bin/console alerts:bestbefore:send
pkt. 3: bin/console integrations:sap:import --from="2021-04-01"

oba polecenia możemy dodać do crona. Jak widać - wrapperem jest w tym przypadku binarka bin/console, która ładuje komendy i ich definicje.

I teraz ciekaw jestem, jak to realizujecie w ASP .Net - interesujący sposób podał @maszrum, na pewno to zgłębię. Pomysłów mam kilka:

  • osoba binarka jako Console Application
  • background task service, o ile nie potrzebuje parametrów
  • na wesoło: endpointy w API, które uruchamiają określone akcje (do crona można podpiąć skrypt, który robi request pod ten endpoint)

Więcej pomysłów nie mam. Przeszedłem przez kilka kursów, ale żaden nie porusza tematów na tym poziomie. Myślę, że to bardzo standardowy problem i powinno być już do niego dość popularne, niejako "standardowe" podejście.

5

W moim (być może ograniczonym) rozumowaniu w kategoriach .Net Twoje wymagania są czymś co obsługuje się na poziomie aplikacji/frameworków, a nie języka per se. Możesz to osiągnąć właśnie za pomocą IHostedService o którym wspomniał maszrum, który możesz uruchomić jako zwykła aplikacja konsolowa lub zainstalować jako Windows Service za pomocą odpowiedniego rozszerzenia. Twój serwis implementujący może zawierać logikę odpowiadającą za wywoływanie odpowiednich zadań, możesz to również odpalać periodycznie przy użyciu Timera. Ponadto na poziomie aplikacji możesz wydzielić zadania do oddzielnych handlerów, np. przy zastosowaniu wzorca mediator. To czy w danym momencie odpalić dane zadanie możesz konfigurować, np. przy zastosowaniu pliku konfiguracji appsettings.json lub przekazując właśnie jako parametry do aplikacji.

3
roSzi napisał(a):

Pogooglowałem trochę i nie widzę specjalnie analogii w świecie .Net. Najlepsze co mi przychodzi do głowy, to dołożyć projekt typu Console Application do solucji, podlinkować zasoby z innych projektów, sparsować args w funkcji Main, zrobić swoje i... tyle.

Można też użyć gotowego rozwiązania do obsługi parametrów i poleceń: https://github.com/natemcmaster/CommandLineUtils

A jak już będziesz miał aplikację konsolową, która umie zrobić to, czego potrzebujesz, to możesz też ją do crona czy innego schedulera podpiąć.

2

Ja robiłem w ten sposób, że była

  • web appka

  • punkty wymiany / kłełełe

  • execution engine / handler / console appka

web appka rejestruje taska/joba w jakimś np. db, a później consolka jest cyklicznie odpalana i sobie odczytuje czy są taski do przemielenia

jakoś zawsze miałem nieuzasadnione obawy aby obsługę zostawiać w web appce

0

Dzięki za ciekawe konkrety.

Na start muszę do projektu dołożyć np. importer danych ze starego systemu, wywoływany ręcznie z wiersza poleceń. Dołożę konsolową aplikację jako kolejny projekt w całej solucji, zlinkuję klasy z projektów core i infrastructure (encje, dbContext etc.). Tak będzie ok?

0

Po każdym dodaniu będziesz musiał zbudować projekt. Średnio wygodne. Szczególnie gdy są to zadanie niezwiązane bezpośrednio z główna aplikacja. Albo nie muszą być.
Ja ostatnio przechodzę z takimi tematami na Pythona ale wtedy nie masz latwego dostępu do kodu c#.

0
jacek.placek napisał(a):

Ja ostatnio przechodzę z takimi tematami na Pythona ale wtedy nie masz latwego dostępu do kodu c#.

Poczułbym się jak w domu, ale uparłem się na próbę "typowego dotnetowego podejścia" do problemu i stąd cały wątek. Kumpel, z którym to klepię, zasugerował dokładnie to samo, bo obaj nie mamy w .net realnego doświadczenia :).

4

Jeśli chcesz dynamicznie dodawać funkcjonalność, to napisz jakiś "core engine" dla ładowania DLLek które implementują jakiś bardzo ogólny interfejs, np. ITaskRunner. Wtedy funkcjonalność będziesz dostarczał w formie pluginow, czyli DLL wrzuconych do jakiejś konkretnej lokacji. Silnik obsługujący to może załadować wszystkie biblioteki z tej lokacji, a następnie znaleźć wszystkie implementacje interfejsu i je uruchomić.

Ewentualnie rozważ jakiś projekt pozwalający użyć C# jak języka skryptowego, np. https://github.com/oleg-shilo/cs-script

3

w C#9 mamy top level programs - wystarczy dodac csprooja i odpalać jako dotnet run

1

Standardowo u mnie rozwiązuje się to tak (cloud native apka):

  1. Projekt WebApi - normalna apka webowa asp.net core - wrzuca message na kolejke, dodaje coś do db
  2. Projekt Webjob (https://docs.microsoft.com/en-us/azure/app-service/webjobs-sdk-get-started) - timer trigery (co x minut/dni), service busy, obsługa kolejek, joby do notyfikacji (np co 4h), importu danych (codziennie albo z kolejki)

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