Kolejkowanie wykonywania zadania przez kilka oddzielnych usług

0

Witam.
Mam problem w kwestii usługi Windows, która już ma tak dużo rzeczy do zrobienia, że w konkretnym interwale nie wyrabia i zaczyna się zapętlać, czasem robi pewne rzeczy podwójnie. Niestety asynchroniczność i tego typu bajery odpadają, ponieważ to są operacje na Comarch Optima, a ona niestety nie ogarnia. Operacje na obiektach COM Optimy są wolne, zamówień jest ponad 1000 dziennie i czasem się robi z tego powodu taki bałagan, że trudno to posprzątać.

Wpadłem na pomysł, aby rozdzielić to na kilka usług i każda z nich będzie miała swoje zadanie do wykonania. Ale... Żeby kolejna usługa mogła coś robić to poprzednia musi skończyć swoje działanie. Przykład:

Etap 1. Usługa sprawdza zamówienia (RO) i odpytuje Allegro o ilość paczek i z jakiego konta (Allegro) jest zamówienie i dopisuje odpowiednie informacje.
Etap 2. Usługa generuje fakturę/paragon do w pełni zrealizowanego dokumentu WZ
Etap 3. Usługa sprawdza zamówienia (RO) czy towar jest na stanie i generuje WZ + generowanie kompletacji (PWP) dla towarów złożonych
Etap 4. Tracking - dopisywanie statusu przesyłki (odpytywanie o status przesyłki DPD lub INPOST)

Pomiędzy tymi etapami są jeszcze statusy magazynowe (pobrane, przygotowywane, gotowe do wysyłki, wysłane). Faktura/paragon oraz tracking wykonywane są dla statusu "wysłane".

  1. Czy jedynym rozwiązaniem jest zrobić jakiś wpis w bazie, który będzie decydował o kolejność wykonywania i na podstawie tego wpisu kolejna usługa będzie wiedziała, że ma teraz pracować?
  2. Czy rozdzielanie tego jest dobrym pomysłem?
  3. Lepiej będzie ustalić jakiś interwał uruchamiania usług czy nasłuchiwać konkretne pole w bazie na zmiany i wtedy uruchamiać?

W planach jest jeszcze dołożyć kolejny etap, który będzie sprawdzał stany magazynowe oraz ceny i aktualizował je na Allegro. Potrzebne jest to głównie do towarów złożonych, których stan magazynowy jest oparty o ilość składników jakie tworzą dany produkt (towar złożony), a takie produkty są kompletowane na bieżąco pod konkretne zamówienie (Etap 3).

2

Jeśli chcesz to robić w jednym procesie to najłatwiej będzie wydzielić każde zadanie do oddzielnego, asynchronicznego modułu i mieć jedno miejsce gdzie będzie to po kolei wywływał- coś takiego:

var resultOne = await doSomethingOne();
var resultTwo = await doSomethingTwo();

Najlepiej zastosuj do tego wzorzec mediator np. przy użyciu biblioteki MediatR, i miej każde zadanie zdefiniowane jako oddzielny request i odpowiadający mu request handler.

Ewentualnie możesz pobawić się w notyfikacje/zdarzenia, i uruchamianie całego łańcucha akcji w kolejności, po zakończeniu poprzedniej.

Jeśli chcesz to robić w oddzielnych procesach to użyj do tego jakiejś kolejki (RabbitMQ, Kafka, cokolwiek), na zakończenie każdego procesu zasygnalizuj to eventem który następnie będzie obsługiwany w wyniku czego rozpoczniesz kolejny proces, później znów event na zakończenie i tak do końca aż wszystko zostanie zrobione.

0

Tak jak napisałem wyżej. Nie mogę użyć asynchroniczności, bo optima się nie zaloguje w drugim wątku jeśli poprzedni się nie zakończy. A takie "czekanie", kolejkowanie mam właśnie teraz i nie ogarnia niestety.

Wszelkiego rodzaju "króliki" i inne tego typu rzeczy wymagają instalacji dodatkowych głupot do poprawnego działania. Nie mam z tym doświadczenia, a za czas poświęcony na ogarnięcie tego nikt nam nie zapłaci.

Padła jeszcze propozycja usługi, która uruchamiała by odpowiednie usługi w określonej kolejności ale to chyba za bardzo przeinżynierowane 🤔

0

Chyba nie rozumiem na czym polega tak naprawdę problem. Skoro to co używasz nie "ogarnia" asynchronicznosci to tym bardziej wydaje mi się że będziesz miał problem jeśli chciałbyś odpalać to w oddzielnych procesach. Wtedy przecież stracisz cały kontekst, to jest stan Twojej operacji.

0

Hej

A nie możesz miec dodatkowej tabeli czy kolumny status i po rozdzieleniu tego procesu na mniejsze każdy z tych procesów sprawdzało by swoje statusy.. nazwij je jak te etapy.

0

Etapy które opisałem wyżej są robione w pewnym interwale, np. co 30 minut (korzystam z Quartz.NET), jeden po drugim. Zajmuje się tym jedna usługa. Ilość dokumentów do przerobienia i "zawrotna" prędkość wykonywania operacji przez Optimę powoduje, że nie skończy robienia wszystkich etapów w ciągu tych 30 minut i znowu robi wszystkie etapy. Przez takie udziwnienie i zazębianie się interwałów miałem sytuację, w której kompletacja (dokument, który tworzy produkt ze składników na podstawie receptury) tworzyła się dwa albo trzy razy. Oprócz tego to próbował zatwierdzać dokumenty po trzy razy co generowało masę błędów, ponieważ ten dokument był już zatwierdzony.

Wydłużenie interwału też parę razy narobiło jakiś głupot, bo usługa nie chodziła przez tydzień z powodu remanentu i nazbierało się tak dużo, że nawet dwie godziny nie pomogły. Zresztą, jaki sens na robienie tego co dwie godziny? Myślę, że system powinien na bieżąco obrabiać dane, aby nie było przestojów w pakowaniu i wysyłce.

Co do asynchroniczności. Jedyne co jest async to metoda realizacji IJob biblioteki Quartz.NET, bo taki jest ich wymóg, a wszelkie metody (etapy) obrabiania danych są synchroniczne, ponieważ:

W obrębie jednego procesu nie można równocześnie logować się kilka razy. Takie operacje muszą być wykonywane synchronicznie. Jeśli jeden wątek się zaloguje, to inny wątek nie może się zalogować, musi czekać aż pierwszy wątek wykona wszystkie operacje i się wyloguje.

Myślę, że głównym problemem jest tutaj Optima, ponieważ obojętnie jak dobrze chciałbym to zrobić to mnie blokują ich zasady i biblioteki, a muszę z nich korzystać, aby dobrze wszystko wprowadzić do bazy.

Jedyne co mi na teraz przychodzi do głowy to podzielić aktualną usługę na kilka usług i uruchamiać je w określonej kolejności usługą główną (zarządzającą). Coś na zasadzie Process.Start() i WaitForExit(), następna usługa Start(), WaitForExit() itd.

@sight
Nie wiem czy dobrze rozumiem. Możesz rozwinąć myśl?

0

A czy musisz to robić w oparciu o samą Optimę? Jakiś czas temu wdrażaliśmy w firmie integrację ERP (nie Optima) z programem serwisowym oraz z aplikacją do ofertowania. Technicznie to była integracja dwóch istniejących aplikacji (serwisowy i ERP) oraz napisanie od zera ofertownika.

Poniewaz koleś, który się tym zajmował znał bardzo dobrze sposób działania ERP'a, to po prostu stworzył swoja aplikację, która działała na bazie ERP, ale nie robiła tego przez jakieś API czy inny mechanizm oferowany przez system ERP, tylko samodzielnie działał na bazie. Wiem, że jest to ryzykowne i wymaga dużo pracy, ale z drugiej strony to wtedy praktycznie nic Cie nie ogranicza - chociażby nie musisz czekać na te 30-minutowe interwały, bo synchronizację (czy inne przetwarzanie) robisz na żadanie/według własnych potrzeb i na swoich warunkach.

0

W przypadku Optimy to tutaj jest dużo więcej roboty względem tego co już mają w swoim API. Na przykład przekształcanie dokumentów:

SerwisHaMag Serwis = (SerwisHaMag)Sesja.CreateObject("Cdn.SerwisHaMag", null);
Serwis.AgregujDokumenty2(308, rRs, magId, 306, out int klasaDok, out int rodzajDok, out int wydanieID);

To jest okrojona wersja. Oczywiście wyżej jest jeszcze logowanie do Optimy i tworzenie sesji ale koniec końców mam wszystko na tacy. Jedna metoda, która wszystko robi automatycznie i przekształca zamówienie do WZ. Jakbym miał to pisać to niestety sam bym sobie prędzej w łeb strzelił niż klient by zapłacił.

Optima kiedyś może i była dobrze zaprojektowana, ale dzisiaj obiekty COM, NET Framework 3.5 to era dinozaurów i na aktualne czasy stwarza to wiele problemów, a klienta to nie obchodzi, bo "ma działać skoro płaci".

1

Generalnie temat o którym piszesz jest mi bliski ponieważ w podobnej logistycznej branży robię. Mamy różne środowiska prazy/integracja tak jak w Twoim przypadku z web api kuriera.. ale zawsze model jest taki ze każde zamówienie ma etapy.. najpierw wpada zamówienie.. potem wypuszczane jest to do realizacji.. potem zwożone.. potem kontrolowane.. pakowane i na końcu załadunek. Cały system składa sie z mniejszych programów i usług i każdy z nich wiec właśnie po statusie danego zamówienia co ma z nim i czy może cos zrobić. Tu dobrze kolega zapytał.. jak dużo Twoje rozwiązane jest zintegrowane z Optimą.. bo jak wiem te aplikacje jest sa za super napisane. Ja my na pewno Twój proces podzielił na małe etapy.. potem łatwiej cos rozbudować lub znaleźć błąd. Dla przykładu robisz sobie pierwsza usługę która sprawdza tylko czy mamy nowe zamówienia a jak mamy to zapisuje to w bazie ze statusem 1. Kolejna jak widzi status 1 odpytuje Allegro o ilość paczek i jak ma odpowiedz a bierzemy pod uwage np brak Internetu to dopisuje do bazy dane i zmienia status 1 -> 2. Do tego robisz sobie index w bazie na tej kolumny status. Kolejna 3 usługa czyli już nasz status 3 to Usługa generuje fakturę/paragon.. nie wiem czy faktury w formacie pdf czy od razu sie drukują czy sa dostępne w aplikacji ale jak to się wykona to zmienia na status 4..

1

Do Twojego problemu idealnie pasuję kolejkowanie MQ rabbit itp. ale jak nie chcesz używać to może po prostu lockować obiekt wykonania zadań i potem jak się wszystko skończy robić release i wtedy odpalać nowy interwał w usłudze windowsa?

Próbowałeś to?

https://docs.microsoft.com/pl-pl/dotnet/csharp/language-reference/keywords/lock-statement

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