Dlaczego anulowany task wykonuje się co kilka godzin :o

0

Hi,

Mam bardzo prosty programik, który sporadycznie sprawdza sobie czy jest coś w pliku, a następnie jeżeli jest, to wyświetla to na konsole, dalej wykonuje Task: woła sobie jakieś zewnętrzne API i czyści plik.

Problem jest taki, że działa to OK, ale następnie co kilka godzin ten Task pomimo bycia anulowanym się nadal wykonuje

while (true)
{
	if (File.Exists(config.Path))
	{
		var content = File.ReadAllText(config.Path);

		if (content.Length > 0)
		{
			Console.WriteLine(DateTime.Now);
			Console.WriteLine(content);
			Console.WriteLine();
			Console.WriteLine();
			try
			{
				var api = new SomeAPIWrapper(config);
				await api.Call(content);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Message);
			}

			File.WriteAllText(config.Path, "");
		}
	}
	else
	{
		Console.WriteLine($"File does not exists: '{config.Path}'");
	}

	await Task.Delay(10000);
}
public class SomeAPIWrapper
{
	public CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
	private readonly Settings _settings;
	private SocketClient _client;

	public DiscordWrapper(Settings settings)
	{
		_settings = settings;
	}

	public async Task Call(string message)
	{
		_client = new SocketClient();

		await _client.LoginAsync(TokenType.Bot, _settings.Token);
		await _client.StartAsync();

		_client.Ready += () => client_Ready(message);

		await Task.Delay(-1, cancelTokenSource.Token);
	}

	private async Task client_Ready(string message)
	{
		await _client.SendMessageAsync(message);
		Console.WriteLine("WTF?"); // enterprise logging solution 
		cancelTokenSource.Cancel();
	}
}

I ku mojemu zdziwieniu jak zostawiłem to noc, to na konsolce miałem taki output:

24.12.2020 01:15:27
TEST


WTF?
A task was canceled. // i od tego momentu już nie powinno nic się dziać do momentu aż w pliku się coś nie pojawi
WTF? // o 2 w nocy
WTF? // o 5 w nocy
WTF? // o 9 rano
WTF? // o 10 rano

z czego może wynikać ten problem? zgaduję że coś z anulowaniem Taska mogę robić nie tak, ale nadal skąd te dziwne godziny? :O

0

Do końca nie widzę jak masz to przekazane.

Jeśli masz Task do anulowania, powinieneś przekazać mu CancellationToken utworzony przez CancellationToken token = source.Token; i przy wywołaniu CancellationTokenSource.Cancel to zadanie będzie anulowane.

0

@bakunet:

W metodzie Call jest robiony await Task.Delay(-1, cancelToken) ten -1 wynika z tego, że "zalogowanie" się w tym zewnętrznym systemie trwa X

await _clientLoginAsync(TokenType.Bot, _settings.Token)

i gdy uda mu się zalogować, to wywoływany jest event Ready i wtedy ja mogę działać, więc się w niego wpinam, robię swoją robotę i tam wywołuję Cancel(), aby ten await z -1 się skończył

i z tego co widzę to tak się dzieję, a przynajmniej na to wygląda, ale po kilku godzinach z jakiegoś powodu jakby ten handler client_Ready się wykonywał.


Tak mnie teraz naszło, może ja po prostu nie odpinam się od tego eventu i on tam gdzieś żyje w pamięci :o

0

@bakunet:

no tak, i ten token pochodzi z public CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

0

@WeiXiao: A próbowałeś takiego podejścia? https://stackoverflow.com/a/40024932

Bądź co bądź, rozumiem że chcesz anulować api.Call() a nie sam Task.Delay? Czemu do api.Call() nie jest przekazywany też ct.Source?

1
        _client = new SocketClient();

        await _client.LoginAsync(TokenType.Bot, _settings.Token);
        await _client.StartAsync();

        _client.Ready += () => client_Ready(message);

Dlaczego event handlera do Ready dopinasz dopiero po zawaitowaniu LoginAsync() i StartAsync()? Ja bym dał go od razu po konstrukcji obiektu _client. Jak dla mnie to czy on się wywoła to kwestia przypadku.

A co do Delay(-1) to rozumiem, że ta konstrukcja służy tylko temu żeby przejść z Event asynchronous pattern do Task asynchronous pattern?

0

Jako że ani Dispose, ani odpięcie mi nic nie dały

public void Dispose()
{
    _client.LogoutAsync().Wait(); // tylko do testów
    _client.Dispose();
    this.Dispose();
}
_client.Ready -= () => client_Ready(message);

to spróbuje tak jak @bakunet pisał

2

ifek tu, ifek tam - pohakowane i nie rzuca błędami ¯\_(ツ)_/¯

public class SomeAPIWrapper
{
	private readonly Settings _settings;
	public bool HasEnded { get; set; }

	public SomeAPIWrapper(Settings settings)
	{
		_settings = settings;
	}

	public async Task Call(string message)
	{
		using (var _client = new SocketClient())
		{
			_client.Ready += () => client_Ready(message, _client);

			await _client.LoginAsync(TokenType.Bot, _settings.Token);
			await _client.StartAsync();

			while (!HasEnded)
			{
				await Task.Delay(5000);
			}

			await _client.LogoutAsync();
		}
	}

	private async Task client_Ready(string message, SocketClient _client)
	{
        await _client.SendMessageAsync(message);
		Console.WriteLine("WTF?"); // enterprise logging solution 
		HasEnded = true;
	}
}

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