Files

3.1 KiB
Raw Permalink Blame History

Join Executor Patterns

Script: join_assigned.py

Key Constants

BATCH_SIZE = 5          # Accounts processed in parallel
BATCH_PAUSE = 15        # Seconds between batches (was 30, lowered for speed)
ACCOUNT_TIMEOUT = 120   # Hard timeout per account (was 60, 50×2.5s avg = 125s)

Error Classification

BAD_REASONS = {
    'CHANNEL_PRIVATE', 'CHAT_WRITE_FORBIDDEN', 'CHANNEL_INVALID',
    'USER_BANNED_IN_CHANNEL', 'INVITE_HASH_EXPIRED', 'INVITE_HASH_INVALID',
    'CHAT_ID_INVALID', 'USERNAME_NOT_OCCUPIED', 'USERNAME_INVALID',
    'CHAT_FORBIDDEN', 'CHAT_RESTRICTED',
}

Join Result Types

Result Meaning
joined Successfully joined
already Already a member (UserAlreadyParticipantError)
flood_N Rate limited for N seconds (auto-waits)
bad_* Chat is private/deleted/invalid
err_* Unknown error (first 50 chars logged)
err_timeout Individual chat operation timed out

Account Status Types

Status Meaning
ok All chats processed
hard_timeout Account took >60s total
no_stringsession No StringSession found
timeout_connect connect() timed out
crash: ... Exception during processing

Async Flow

main() → for each batch of 5 accounts:
  → asyncio.gather(process_with_timeout(acc) for acc in batch)
  → process_with_timeout → asyncio.wait_for(process_account, timeout=60)
  → process_account:
    → client.connect() [10s timeout]
    → client.get_me() [5s timeout]
    → for each chat:
      → get_entity(username) [10s timeout]
      → JoinChannelRequest(entity) [10s timeout]
      → sleep(0.5-1.5s)
    → client.disconnect()

Account Lookup

Accounts are identified by index in the sorted OK list:

ok_accounts.sort(key=lambda a: a.get("phone", ""))
# ...
global_idx = i + idx
acc_key = f"account_{global_idx + 1}"
acc_chats = assignments.get(acc_key, [])

StringSession Lookup

Tries phone first, then name:

ss = string_sessions.get(phone) or string_sessions.get(name)

Progress Persistence

# Saved every batch:
{
    "batch_num": 42,
    "total_joined": 352,
    "accounts_processed": 210
}

# Joined chats saved every 10 batches:
{
    "baraholllkamariupol": {
        "username": "baraholllkamariupol",
        "id": "1856532726",
        "title": "Барахолка...",
        "participants": 21513,
        "joined_by": "12894827641"
    }
}

Performance Observations

  • 50 chats/account × 120s timeout: ~28-36 joins per 58-account process
  • ~25% of accounts succeed (ok), ~40% hard_timeout, ~20% timeout_connect, ~15% no_stringsession
  • 50 chats × 2.5s avg = 125s → 120s is tight. Some accounts with slow connections hit hard_timeout
  • timeout_connect accounts have network/DC issues — not recoverable per-run
  • 3 parallel processes × 58 accounts: ~81 new joins, ~17 min runtime
  • 0 flood, 0 bans — safe for mass operations
  • BATCH_PAUSE=15s (was 30s) — sufficient to avoid rate limits, 2x faster
  • Together with 3-way parallel: ~6x speedup vs original single 30s-pause process