1

I do SAP Gui Scripting in VB.Net with .Net Framework 4.8. At some point the SAP will be unresponsive due to circumstances out of my control, and the called function will completely block further execution forever. In this case i want to safely exit the code.

In order to overcome this obstacle where the SAP function call completely blocks execution my approach is to create a New System.Threading.Task, execute the blocking function in it and after a given timeout cancel the operation. I'd also like to be informed if the element had been found.

For this reason i created the following code mostly by reading docs.mycrosoft.com

Dim propablyBlockingFn = Function () 
  Dim found = False

  While not found
    'code that interacts with sap and will either set found to true or completly block execution
  End While

  Return found
End Function

Dim timeout = 5000 'ms
Dim t As Task(Of Boolean) = Task.Run(fn)
Dim cts As New CancellationTokenSource()
Dim token As CancellationToken = cts.Token

Dim taskRef = t.Wait(timeout, token)

If Not taskRef Then
    cts.Cancel()
End If

Dim exists = t.Result 'it will stuck here
t.Dispose()

However, at the point where i try to read the Result of the function, the code wont execute any further and the cancel call does not have any effect.

Does anyone have an idea?

TheDomis4
  • 122
  • 1
  • 13
  • 1
    `cts.Cancel()` should result in an `OperationCanceledException` issuing from the `Wait` call. Note that you are canceling the *wait operation*, not the *task itself*. If you want to be able to cancel the task itself, you need to put a cancellation token argument on the source of the task and periodically check for requested cancellation on the token (and/or you need the underlying SAP system to support cancellation). – Craig Dec 06 '21 at 14:45
  • Ah, so i got the concept wrong. The token will only be ... a token and i'm responsible to handle it. Unfortunatelly this part of the SAP System is not compatible with such cancellation methods and will just block code execution. My next best guess would be using `Threads`, which have an `abort()` Method. Would that be more what i'm looking for? – TheDomis4 Dec 06 '21 at 17:57
  • 1
    `Thread.abort` might work, but if I remember right `abort()` should be avoided unless absolutely necessary (and maybe should be avoided even then---it's not really designed to be used). It's very unfortunate if they only support blocking calls without a cancellation mechanism. Note, though, that if you have some sort of intermediate asynchronous layer, you can accept cancellations there and have it look to the user like you dropped it even if it's still running in the background. – Craig Dec 06 '21 at 19:01
  • thanks, yes unfortunatelly it runs autonomous on a windows server. So, even the asynchronous layer will have some sort of memory leak. I somehow hoped there would be some garbage collection magic when i cancel a task/thread. So it seems i got to choose between plaque and cholera :) thanks nonetheless. I've got some options now. And we do keep restarting them on schedule, so it might not (yet) be a big of a problem – TheDomis4 Dec 06 '21 at 20:08
  • 1
    Regardless of whether you're working with a `Task` or a thread, cooperative cancellation is the only thing that will really work. Non-cooperative cancellation either isn't supported at all (`Task`) or is likely to lead to resource leaks and/or an unstable state (thread abort). But some "leaks" are worse than others---a dangling operation in an async layer will cost resources during the time it takes to complete, but I would expect it to still clean itself up once it's done. – Craig Dec 06 '21 at 20:15

1 Answers1

0

I've found a last resort solution after reading the following answer. Keep in mind that sideeffects may happen. But they would be even worse if in this case i won't abort the Thread.

Dim taskThread As Thread = Nothing
Dim propablyBlockingFn = Function () 
  taskThread = Thread.CurrentThread 'Get the Thread the Task is running in
  Dim found = False

  While not found
    'code that interacts with sap and will either set found to true or completly block execution
  End While

  Return found
End Function

Dim timeout = 5000 'ms
Dim t As Task(Of Boolean) = Task.Run(fn)

Dim taskRef = t.Wait(timeout)

If Not taskRef Then
    taskThread.Abort() 'Abort the Thread
End If

Dim exists = t.Result
TheDomis4
  • 122
  • 1
  • 13