That sounds a lot like Node.js’s callbacks —with the associated callback hell that eventually got resolved through async/await.
These days, I tend to look at Go’s standard library, rather than Python’s, for inspiration on how to implement certain things in Fortran.
Go’s approach, when things may fail, is to always return an error object —which, in Fortran terms, means using subroutines rather than functions.
And there’s also the factory-function-and-then-methods approach, something like:
module mod1
type :: process
...
contains
procedure :: process_id
procedure :: run ! synchronous
procedure :: start ! asynchronous
procedure :: wait ! wait for asynchronous
...
generic :: write(formatted) => write_formatted_process
...
end type
interface process
module procedure process_new
end interface
contains
function process_new(...) result(new)
type(process) :: new
...
end function
pure function process_id(this) result(pid)
...
end function
subroutine start(this, ...)
...
end subroutine
subroutine run(this, ..., output, error)
...
character(:), allocatable, optional, intent(out) :: output
...
end subroutine
subroutine wait(this, output, error)
...
end subroutine
...
end module
See, for example, the exec package.
Cooperative locking comes to mind —e.g., if two applications use the same locking mechanism provided by stdlib.