Threads and accounts
How a Multogram module runs in several threads: what a thread is, how to hand accounts out to threads without repeats, when a module's task ends, shared and local data, the task's log and statistics, running functions in parallel.
A module runs as a task: the user fills in the module form, chooses the number of threads and starts it. Each thread runs the Main function from the start, independently of the others. So a module's scenario is written so that each thread takes its own share of the work.
What a thread is
A thread is one independent pass through the scenario. Each thread has its own local variables and its own Telegram session, so threads don't interfere with each other. An error in one thread ends only that thread — the others keep working. Resources — the form's values — are shared by all threads.
How to hand accounts out to threads
The selected accounts arrive in the accounts resource as one list shared by all threads. So that two threads don't take the same account, a thread takes an account from the list with the Get Resource Value action and its Take Item parameter: the item is removed from the list and given only to this thread.
The new module template already does this in the Main function:
Get Resource Value accounts · First item → [[account]]
WHILE [[account]] != ""
TRY Call Function ProcessAccount ([[account]])
CATCH Add Log "[[account]].phone: error — [[_error]]"
Get Resource Value accounts · First item → [[account]]Each thread works while there are accounts on the list, and then ends by itself. This way the module works correctly with any number of threads: if there are fewer threads than accounts, each processes several. Add your own work with an account to the ProcessAccount function — see Your first module. The same technique works for any shared list — targets, links, file lines.
When a module's task ends
How the task ends is set in the constructor's Threads window. A module whose mode was never chosen makes one pass in each thread: its task ends when every thread has finished the Main function. A thread that ended with an error is not started again: the accounts it did not take are taken by the other threads.
Hence the rule for your own scenario: Main must keep working while there is work, rather than process one account and finish.
Any module can choose another mode:
| Mode | When the task ends |
|---|---|
| Continuously | Only when stopped manually: a thread that has finished Main starts again |
| One pass | When every thread has gone through Main once |
| Set amount | After N runs of Main across all threads |
| Until N succeed | When N runs have ended successfully |
Stop after failures adds to any mode and ends the task after N failed runs.
While the accounts field is shown, the Threads window recommends One pass: accounts are handed out once, and a thread started again finds none left. Another mode suits a module that goes through every account on each pass without taking them off the list, or a module without accounts — with the accounts field hidden from its form. A task in Multogram ends the same way as a run started with Start in the constructor's preview.
A module that should run until stopped manually (for example, watch a chat) either spins a loop inside Main and doesn't leave it, or runs Continuously.
Thread data
| Job | How to solve it |
|---|---|
| One account's data | Local variables — Set Variable, action results |
| A counter shared by all threads | Set Global Variable, Increment Global Variable |
| Figures for the user: sent, errors, processed | The Statistics module — indicators shared by all threads |
| What is happening in the task | Add Log from the Logger module — the lines are visible in the task log |
| The thread's number, status and data | The Threading module |
| End a thread with success or an error | Complete Thread, Fail Thread |
The session stays inside the thread
Sign in to an account and work with it in one thread, and close the session after the work with the Destroy Session action. Then threads don't grab each other's sessions, and a failure of one account doesn't affect the others.
Parallel functions inside a thread
The Tasks module runs a function in a separate thread without waiting for it to finish — for example, to check several channels at once.
| Action | What it does |
|---|---|
| Start Task | Runs a function in a new thread, returns the task ID |
| Wait for Result | Waits for the task to finish (with a timeout) and gets its result |
| Check Completion, Get Task Status | Find out whether the task has finished without waiting for it |
| Cancel Task | Stop the task |
For ordinary work with accounts you don't need this: the module's threads already work in parallel.
Recommendations
- One thread, one account at any moment. Don't use one session from several threads.
- Pauses go into resources. Move the delay between Telegram actions into a form field so the user tunes it to their accounts — see Telegram limits.
- Write to the log. A short line for each account — "sent", "could not sign in" — makes finding problems on the user's side much easier.
Updated
Resources and the module form
{{name}} resources in the Multogram Modules Constructor — the fields of a module's settings form: field types, required fields, groups in the layout manager, visibility conditions, translations, test values and the account picker field.
Your own code
The Code Execution module in the Multogram Modules Constructor: built-in JavaScript, Python, Node.js, CMD, Bash and PowerShell. How variables and resources are inserted, how to return a result, packages.