179 lines
4.5 KiB
Plaintext
179 lines
4.5 KiB
Plaintext
SECTION IV: Concurrency and Asynchrony
|
||
|
||
AVAP implements a thread-based concurrency model that enables fire-and-forget execution or parallel execution with later synchronization. This is essential for tasks such as email dispatching, log processing, or querying multiple external APIs simultaneously.
|
||
|
||
4.1 Launching Background Processes (go_async)
|
||
|
||
The go_async command extracts a block of code from the main sequential flow and places it into a parallel execution queue.
|
||
|
||
Interface
|
||
go_async(thread_id)
|
||
Execution Mechanics
|
||
|
||
Identification:
|
||
The programmer assigns a thread_id (a string or variable) to reference the process later.
|
||
|
||
Forking:
|
||
When invoked, the AVAP engine creates a new native thread. The main flow immediately continues to the next instruction after the go_async block.
|
||
|
||
Context Isolation:
|
||
The asynchronous thread inherits a snapshot copy of the variable state at the moment of invocation, allowing it to operate safely without interfering with the main thread.
|
||
|
||
Example: Immediate Response with Long-Running Process
|
||
addParam("email", destination)
|
||
|
||
go_async("email_dispatch")
|
||
// This block takes 5 seconds, but the API does not wait
|
||
mail_service.send(destination, "Welcome to AVAP")
|
||
end()
|
||
|
||
addVar(msg, "Your email is being processed in the background")
|
||
addResult(msg)
|
||
// The client receives the response in milliseconds
|
||
4.2 Result Synchronization (gather)
|
||
|
||
When the main flow requires data generated by an asynchronous thread to proceed, the gather synchronization mechanism is used.
|
||
|
||
Interface
|
||
gather(thread_id, timeout)
|
||
Specifications
|
||
|
||
thread_id:
|
||
The identifier used in the go_async command.
|
||
|
||
timeout (Seconds):
|
||
Maximum time the main thread will wait. If the asynchronous thread does not finish within this period, AVAP raises an exception that can be caught (see Section III).
|
||
|
||
Technical Behavior
|
||
|
||
Controlled Blocking:
|
||
The main thread is suspended until the specified thread_id completes.
|
||
|
||
State Recovery:
|
||
Once synchronized, any variables modified within the asynchronous thread are merged back into the main thread’s context.
|
||
|
||
4.3 Optimized Parallel Execution (Fan-Out Pattern)
|
||
|
||
AVAP allows launching multiple threads and then waiting for all of them, reducing total execution time to the duration of the slowest thread instead of the sum of all execution times.
|
||
|
||
Example: Querying Multiple Databases
|
||
go_async("db_north")
|
||
data_north = north_connector.query("SELECT...")
|
||
end()
|
||
|
||
go_async("db_south")
|
||
data_south = south_connector.query("SELECT...")
|
||
end()
|
||
|
||
// Wait for both (Maximum 10 seconds)
|
||
gather("db_north", 10)
|
||
gather("db_south", 10)
|
||
|
||
// Combine results using Section I mechanisms
|
||
total_result = data_north + data_south
|
||
addResult(total_result)
|
||
4.4 Promise State in Output
|
||
|
||
As mentioned in Section II, if a variable that is still being processed in an asynchronous thread is passed to addResult, AVAP manages the response intelligently:
|
||
|
||
If the thread is still running:
|
||
The output JSON will display "variable": "promised" or the thread ID.
|
||
|
||
If the thread failed:
|
||
The error is logged internally and the variable is set to None.
|
||
|
||
If gather was used before addResult:
|
||
The fully processed real value is returned in the response.
|
||
|
||
Examples
|
||
|
||
1. Background Process Fire-and-Forget
|
||
|
||
Code snippet
|
||
|
||
go_async("notification_thread")
|
||
// This block runs on its own
|
||
RequestPost("https://hooks.slack.com/...", {}, body, r)
|
||
end()
|
||
|
||
2. Synchronization (Gather)
|
||
|
||
Code snippet
|
||
|
||
go_async("heavy_calc")
|
||
result = (500 * 250) / 3
|
||
end()
|
||
gather("heavy_calc", 10) // Waits until it finishes
|
||
addResult(result)
|
||
|
||
3. Connector Parallelism
|
||
|
||
Code snippet
|
||
|
||
go_async("db_1")
|
||
res1 = db1.query("SELECT...")
|
||
end()
|
||
go_async("db_2")
|
||
res2 = db2.query("SELECT...")
|
||
end()
|
||
|
||
4. Gather with Safety Timeout
|
||
|
||
Code snippet
|
||
|
||
gather("external_process", 5)
|
||
// If it doesn't finish in 5s, the script continues or fails depending on config
|
||
|
||
5. Using "Promised" State
|
||
|
||
Code snippet
|
||
|
||
go_async("long_task")
|
||
final = "Finished"
|
||
end()
|
||
addResult(final) // You will see "promised" in the JSON
|
||
|
||
6. Validation After Gather
|
||
|
||
Code snippet
|
||
|
||
gather("data_thread", 2)
|
||
if(thread_data, None, "!=")
|
||
addResult(thread_data)
|
||
end()
|
||
|
||
7. Multi-Threading for Auditing
|
||
|
||
Code snippet
|
||
|
||
go_async("audit_thread")
|
||
ormDirect("INSERT INTO audit...", r)
|
||
end()
|
||
|
||
8. Dynamic Gather in a Loop
|
||
|
||
Code snippet
|
||
|
||
startLoop(h, 1, 3)
|
||
gather("thread_${h}", 1)
|
||
endLoop()
|
||
|
||
9. Asynchronous Tax Calculation
|
||
|
||
Code snippet
|
||
|
||
go_async("tax_engine")
|
||
total_tax = total * 0.21
|
||
end()
|
||
|
||
10. Try-Except Inside an Async Thread
|
||
|
||
Code snippet
|
||
|
||
go_async("safe_thread")
|
||
try
|
||
// Task that may fail
|
||
exception(err)
|
||
// Log the error locally
|
||
end()
|
||
end() |