Zakończenie Task'a

0

Witam,
mam problem z aplikacją.
Mianowicie mam uruchomiony Task i tam wykonują się pewne metody i funkcje, mam założony CancellationTokenSource, żeby po określonym czasie Task zakończył. Niestety przychodzi pewien czas kiedy aplikacja wisi na pewnej funkcji i może tak stać póki sam ją nie zrestartuje. CancellationTokenSource nie działa, nie kończy Task'a. Aplikacja jest serwisem więc bez sensu, kiedy muszę ręcznie ją restartować. Jest może jakiś sposób by aplikacja kończyła Task z automatu jak funkcja po pewnym czasie nie odpowiada?

0
bymbyn napisał(a):

CancellationTokenSource nie działa, nie kończy Task'a

Zdajesz sobie sprawę, że CancellationToken nie działa magicznie, tylko Task musi mieć w kodzie explicite sprawdzenie, czy trzeba się skończyć?

bymbyn napisał(a):

Jest może jakiś sposób by aplikacja kończyła Task z automatu jak funkcja po pewnym czasie nie odpowiada?

Nie ma, ponadto await lub ContinueWIth (jeżeli ich używasz) nie pozwalają na trywialne zrobienie tego. Najprościej jest odpalić drugie zadanko Task.Delay(timeout), a potem zrobić Task.WhenAny(firstTask, delayTask) i sprawdzić, który skończył się pierwszy.

Dygresja: jedną z podstawowych zasad pisania porządnego kodu wielowątkowego jest "zawsze czekaj z timeoutem". Jeżeli gdziekolwiek czekasz (czy to explicite przez Wait lub await, czy to implicite przez jakiś ContinueWith), zawsze ustawiaj timeout, bo inaczej kiedyś Cię to kopnie. Najlepiej jest to opakować w jakieś rozszerzenie i wtedy typowy kod asynchroniczny wygląda await Foo().ConfigureTimeout().ConfigureAwait(false), co wygląda paskudnie, ale przynajmniej robi robotę.

0

Tak jak wyżej napisał już ktoś, Cancellation token nie działa magicznie. Trzeba zarejestrować token source i zrobić jakiś warunek + sprawdzenie, żeby było wiadome co ma się stać gdy cancellation token będzie "wywołany". Tak naprawdę taki token możesz zastąpić zwykłym obiektem który zawiera sobie flagę bool stop = false; i w pętli sprawdzać czy nie została zmieniona na true a jeśli została to kończysz zadanie.

Poczytaj sobie o gracefull shutdown, fajnie jest coś takiego zaimplementować u siebie jak masz np Background Services w swojej apce i niektóre mogą zostać zamknięte z automatu a inne muszą poczekać na "dokończenie" aktualnie działąjących zadań z jakimś limitem czasowym

0

#Afish dzięki za odpowiedź.
Ta metoda Task.WhenAny(firstTask, delayTask) robi to co mam robić i o to mi chodziło, jednak martwi mnie to że pierwszy Task nadal jest w pamięci i czeka na zakończenie, co skutkuje przyrostem użycia pamięci. Jest może sposób by, że tak się wyrażę, w sposób "perfidny" zabić ten Task?

0

Nie, nie można ubić Taska ot tak, co więcej, byłoby to bardzo złe.

0

Czyli co jakiś tam czas będę musiał mój serwis ręcznie restartować by pozbyć się "śmieci" z pamięci.

Ok, dzięki #Afish za pomoc.
Wątek uważam za zakończony i rozwiązany

2

Jeśli Twój task się zawiesza albo powoduje wycieki pamięci, masz poważny błąd w kodzie - stwierdzenie dobra, będę se ten serwis restartował co godzinę nie jest rozwiązaniem i na 99% zaboli w przyszłości albo Ciebie, albo (co gorsza!) osobę, która po Tobie ten kod przejmie.

Wyobrażasz sobie, aby np. hydraulik Ci powiedział w dni parzyste, codziennie między piątą a szóstą rano musi pan uderzyć młotkiem w trzecią rurę, w połowie jej długości - w innym wypadku zaleje panu piwnicę, kwitując, że to dobrze wykonana robota?

0
Patryk27 napisał(a):

Jeśli Twój task się zawiesza albo powoduje wycieki pamięci, masz poważny błąd w kodzie - stwierdzenie dobra, będę se ten serwis restartował co godzinę nie jest rozwiązaniem i na 99% zaboli w przyszłości albo Ciebie, albo (co gorsza!) osobę, która po Tobie ten kod przejmie.

Wyobrażasz sobie, aby np. hydraulik Ci powiedział w dni parzyste, codziennie między piątą a szóstą rano musi pan uderzyć młotkiem w trzecią rurę, w połowie jej długości - w innym wypadku zaleje panu piwnicę, kwitując, że to dobrze wykonana robota?

To masz jakiś pomysł by zakończyć Task w którym jest funkcja z zewnętrznej biblioteki i ona stoi? Niestety do biblioteki nie mam dostępu.
Dokładnie chodzi o biblitekę ClaRUN. Jest tam funkcja AttachThreadToClarion(1); i na niej aplikacja mi stoi.

0

W jakich warunkach się zawiesza?

0

No właśnie trudno określić, przeważnie dzieje się to w nocy, mam podejrzenie, że może chodzić o baz danych, ale przed wywołaniem tej funkcji pytam bazę o dane i działa. Może też chodzić o jakiś serwis CDN, ale nie wiem jaki.

I wtedy mój serwis stoi póki go ręcznie nie zrestartuje

0

Zrób zrzut pamięci albo zapnij debugger i wstrzymaj aplikację, to zobaczysz wszystkie stosy.

Dygresja: Już wielokrotnie miałem sytuację, gdzie zewnętrzne biblioteki miały deadlocki, więc o ile rozwiązanie przez ubijanie taska nie jest eleganckie, to jednak w życiu bywa różnie.

0

Też robiłem zrzut pamięci ale pokazało że stoi na AttachThreadToClarion(1); i nic więcej

0

No a co to znaczy? Co to dokładnie robi? Czym jest Clarion? Dlaczego nie może się doczekać?

0

Co to robi to nie wiem, ale zgodnie z dokumentacją API "Przed pierwszym wywołaniem funkcji API dla każdego nowego wątku tworzonego przez aplikację wykorzystującą API należy zawołać funkcję AttachThreadToClarion z parametrem 1."

1

No to za bardzo nie da się pomóc, jak nie podasz konkretów.

  1. Przede wszystkim podaj linki do biblioteki, bo googlowanie "nuget ClaRUN" niewiele mi dało.
  2. Umiesz to odtworzyć na jakimś małym kodzie?
  3. Masz zrzuty pamięci? Jak tak, to załącz je tutaj, wraz z symbolami. Tylko miej na uwadze, że wtedy da się podejrzeć cały kod Twojej aplikacji, więc jak masz tam coś poufnego, to nie załączaj nic, tylko odtwórz to w osobnej aplikacji.
0

To jest biblioteka dołączona do CDNXL więc na nuget jej nie ma. Niestety nie mogę odtworzyć tego błędu na mniejszym kodzie, ponieważ tak jak wcześniej już pisałem nie wiem jak ten błąd wywołać. Mam podejrzenia, ale je wykorzystując nie doSZEDŁem do tego błędu. Wiem tylko tyle, że wywala w nocy, ale też nie zawsze, mam założone logi. Z dokumentacji nic nie wynika, ponieważ tam są dosłownie 2 zdania, z czego jedno tu załączyłem. Drugie mówi to: "Aby w systemie Comarch ERP XL (platforma programistyczna Clarion 8) podpiąć API do wątku clarionowego, należy zaprototypować funkcję AttachThreadToClarion z biblioteki ClaRUN.DLL"

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