Skip to content

Instantly share code, notes, and snippets.

@Karolis2011
Last active January 24, 2022 19:12
Show Gist options
  • Save Karolis2011/4351f3ae54fe89a4f6580947aec48076 to your computer and use it in GitHub Desktop.
Save Karolis2011/4351f3ae54fe89a4f6580947aec48076 to your computer and use it in GitHub Desktop.
#define ASYNC_DEFAULT "snowflake__thing_should_dnot_bebused"
#define istask(t) istype(t, /task)
/task
parent_type = /datum
VAR_PRIVATE/object_src = ASYNC_DEFAULT
VAR_PRIVATE/result = ASYNC_DEFAULT
VAR_PRIVATE/is_complete = FALSE
var/error = null
/task/New(var/obj_src, var/return_value)
if(obj_src != null)
object_src = obj_src // TODO: Wekref
if(return_value != null)
result = return_value
/task/proc/isComplete()
return is_complete
/task/proc/Wait()
__internal_wait()
/task/proc/WaitResult()
__internal_wait_result()
/task/proc/GetResult()
return __internal_get_result()
/task/proc/__internal_complete()
is_complete = TRUE
/task/proc/__internal_result(var/result)
src.result = result
/task/proc/__internal_return(var/result)
is_complete = TRUE
src.result = result
/task/proc/__internal_handle_error(var/e)
error = e
// TODO: Make it handle error
/task/proc/__internal_wait()
while(!is_complete)
sleep(world.tick_lag)
/task/proc/__internal_wait_result()
while(result == ASYNC_DEFAULT)
sleep(world.tick_lag)
/task/proc/__internal_get_result()
if(src.result == ASYNC_DEFAULT)
return null
else
return src.result
#define BEGINASYNC set waitfor = FALSE; RETURN_TYPE(/task); . = new /task(src, .); try
#define ENDASYNC catch (var/e) { (.).__internal_handle_error(e) } (.).__internal_complete(); return;
#define ARETURN(value) (.).__internal_return((value)); return;
#define ARESULT(value) (.).__internal_result((value));
#define AWAIT(task) (task).__internal_wait();
#define AWAITR(v, task) (task).__internal_wait(); v = ((task).__internal_get_result());
#define AWAITRESULT(v, task) (task).__internal_wait_result(); v = ((task).__internal_get_result());
/proc/TaskWhenAny(...)
BEGINASYNC
var/list/tasks = args
if(islist(args[1]))
tasks = args[1].Copy()
for(var/task in tasks)
ASSERT(istask(task))
while(TRUE)
for(var/task in tasks)
var/task/T = task
if(T.isComplete())
ARETURN(T)
sleep(world.tick_lag)
ENDASYNC
/proc/TaskWhenAll(...)
BEGINASYNC
var/list/tasks = args
if(islist(args[1]))
tasks = args[1].Copy()
for(var/task in tasks)
ASSERT(istask(task))
while(tasks.len)
for(var/task in tasks)
var/task/T = task
if(T.isComplete())
tasks -= T
sleep(world.tick_lag)
ENDASYNC
/proc/makeHttpRequestAsync(var/url, var/body)
BEGINASYNC
// Code using sleep(delay) ir AWAIT(task)
// ...
sleep(pick(1,2,3,4,5,6,7,8))
ARETURN(url)
ENDASYNC
/proc/doMutipleRequestsAsync()
BEGINASYNC
var/task/githubTask = makeHttpRequestAsync("https://api.github.com/ping", null)
var/task/auroraTask = makeHttpRequestAsync("https://api.aurorastation.org/someLongTask", null)
var/task/cTask = TaskWhenAll(list(githubTask, auroraTask))
// We can wait for all tasks to finish
AWAIT(cTask)
// Or we can wait just for any of them
var/task/finishedTask
cTask = TaskWhenAny(list(githubTask, auroraTask))
AWAITR(finishedTask, cTask)
if(finishedTask == auroraTask)
world.log << "Aurora task finished first"
if(finishedTask == githubTask)
world.log << "GitHub task finished first"
// Or we can wait only for the result, useful when we need the result ASAP, but proc still has work to do. In such case proc would use ARETURNR(result)
var/response
AWAITRESULT(response, auroraTask)
ENDASYNC
/proc/NormalProc()
var/task/myTask = doMutipleRequestsAsync()
myTask.Wait() // Do sleep like lock
myTask.WaitResult() // Similar to wait, but it doesn't wait for completion, only the result, will be the same as Wait() if async proc doesn't use ARETURNR.
world.log << myTask.GetResult() // Access result safely, crashes if result is not there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment