## 4 An Architecture for Edge-Fog-Cloud Offloading
This includes handling job-stealing requests, processing completed results, delegator functioning as a victim when a worker steals jobs from the delegator (described in Algorithm 6), expiring the oldest jobs (detailed in Algorithm 7), and sending termination signals upon task completion (detailed in Algorithm 8). ```
1:Input: Job pool \(\mathcal{J}\), steal limit \(L_{s}\), chunk size \(C_{s}\)
2:Output: Stolen job list \(\mathcal{J}s\)
3:Initialise \(\mathcal{J}s\leftarrow\emptyset\)
4:if\(\mathcal{J}\
eq\emptyset\)then
5:if\(|\mathcal{J}|>L_{s}\)then
6:\(job\leftarrow\) get first job in \(\mathcal{J}\)
7:endif
8:whilejob \(\
eq\) null do
9:\(\mathcal{J}s\leftarrow\mathcal{J}s\cup\{job\}\)\(\triangleright\) Add job to stolen list
10:if\(|\mathcal{J}|\leq L_{s}\)then
11:break
12:endif
13:if\(|\mathcal{J}s|\geq C_{s}\)then
14:break
15:endif
16:\(job\leftarrow\) get next job in \(\mathcal{J}\)
17:endwhile
18:endif
19:Transmit \(\mathcal{J}s\) to worker
```  
**Algorithm 6** Delegator's victim thread ```
1:Input: Pending results list \(\mathcal{R}\)
2:Output: Expired jobs \(\mathcal{J}_{\text{expired}}\)
3:Initialise \(\mathcal{J}_{\text{expired}}\leftarrow\emptyset\)
4:if\(\mathcal{R}\
eq\emptyset\)then
5: Select worker \(w_{ex}\) with the oldest pending jobs from \(\mathcal{R}\)
6:\(\mathcal{J}_{\text{expired}}\leftarrow\text{pending jobs of }w_{ex}\)
7:endif
8:return\(\mathcal{J}_{\text{expired}}\)
```

**Algorithm 7** Delegator's job expiration method

Over the course of program execution, any participating device can assume both roles of _thief_ and _victim_. Hence, the worker can'steal' from the delegator and the delegator can also'steal' from workers if its own job pool is empty, but the task is not yet completed (see Algorithm 2). When a device receives a steal request, depending on its available job queue, it can decide to become a victim (see Algorithm 6). The victim then removes a \(C_{s}\) number of jobs (i.e., a chunk) from its own job list, and transmits them to the thief. The chunk size, \(C_{s}\), defines the number of jobs a node can steal at a time. It is set as a small percentage of the total job count to minimise loss and enable easy reassignment if the worker disconnects. * Stealing decisions: When the delegator steals from workers, workers are traversed sequentially in the order they connected to the delegator. The delegator attempts to steal jobs from each worker until successful or until all workers have been tried. Workers can only steal from the delegator due to an implementation constraint in peer-to-peer (P2P) connection protocols. In technologies such as Bluetooth and Wi-Fi Direct, only a star topology is supported, not a mesh. As a result, P2P connections between workers are not feasible. * Conflict avoidance: The delegator maintains a synchronised lock on the job pool \(\mathcal{J}\) during job allocation to prevent race conditions. This ensures that jobs are not simultaneously assigned to multiple workers. * Complexity and overhead: The sequential worker selection ensures that worker traversals are \(O(n)\), where \(n\) is the number of connected workers. Locking and job allocation operations remain \(O(1)\), ensuring low overhead for each steal request. * Fault tolerance: Worker heartbeats and job expiry are two main fault tolerance mechanisms in the framework. Each worker periodically sends a 'heartbeat' signal to the delegator to indicate its availability (see Algorithm 5). Other communications, such as job results, are also considered as heartbeats. If no heartbeat is received from a worker for a pre-determined consecutive interval, the delegator deems the worker as disconnected, and their assigned jobs are returned to the job pool for reassignment. If a job remains uncompleted beyond a predefined expiry time, it is marked as 'expired' and returned to the job pool, allowing other nodes, including the delegator, to process it (see Algorithms 5 and 7).