en-US/about_Mgx_Tuning.help.txt

TOPIC
    about_Mgx_Tuning

SHORT DESCRIPTION
    Default settings, hard ceilings, and tuning guidance for large tenants.

LONG DESCRIPTION
    Mgx ships with conservative defaults to prevent accidental self-DoS
    against your tenant. Every tunable has a hard ceiling enforced at the
    property level -- invalid values throw rather than silently apply.

    Use Set-MgxOption to change settings at runtime. Only explicitly passed
    parameters are modified; all others retain their current values. Use
    Set-MgxOption -Reset to restore all defaults.

CLIENT-SIDE RATE LIMITING (ON BY DEFAULT)

    Setting Default Hard Max Purpose
    ------- ------- -------- -------
    RateLimitBurst 200 10,000 Token bucket burst capacity
    RateLimitPerSecond 50 10,000 Sustained request rate
    RateLimitQueueLimit 500 100,000 Queued requests before rejection

    Disable explicitly with Set-MgxOption -NoRateLimit.

RETRY BUDGET CAPS

    Setting Default Hard Max Purpose
    ------- ------- -------- -------
    MaxRetryAttempts 7 50 Retries per request
    MaxRetryAfterSeconds 120s 600s Caps server Retry-After delays
    TotalTimeoutSeconds 300s 3,600s Total time across all retries
    AttemptTimeoutSeconds 30s 300s Per-request timeout

CIRCUIT BREAKER

    Setting Default Hard Max Purpose
    ------- ------- -------- -------
    CircuitBreakerFailureRatio 10% 100% Failure ratio to trip
    CircuitBreakerMinThroughput 40 1,000 Min requests before evaluating
    CircuitBreakerSamplingDurationSeconds 30s 300s Evaluation window
    CircuitBreakerDurationSeconds 15s 300s Open-state duration

    Trips on 500/502/503/504 (server errors). Does NOT trip on 429 -- that
    is expected throttling, not failure.

BATCH CONSTRAINTS

    Setting Default Hard Max Purpose
    ------- ------- -------- -------
    BatchChunkConcurrency 1 10 Concurrent batch chunks
    BatchItemsPerSecond 20 1,000 Inter-chunk pacing (items/sec)
    Batch size 20 20 Items per /$batch POST (Graph limit)
    Per-item retries 3 3 Retries for failed items in a batch

    Sequential chunk execution (default) paces at 20 items/sec to stay under
    Graph's write throttle ceiling.

    Pacing adapts to what the tenant actually tolerates. A 429 halves the write
    rate, down to a floor of 2 items/sec, and the reduced rate carries across
    Invoke-MgxBatchRequest calls so a loop of small batches does not immediately
    get throttled again. It also climbs back: every two consecutive chunks
    without a 429 add a tenth of the configured rate, and once no throttling has
    been seen for five minutes the configured rate is restored outright. Run
    Invoke-MgxBatchRequest with -Verbose to see each adjustment.

WRITE COST: PACE BY WRITES, NOT ITEMS

    BatchItemsPerSecond paces batch items, but Graph throttles directory
    writes. Those are the same thing only when each item performs one write.
    A compound item multiplies the true rate:

        Item shape Writes per item
        ---------- ---------------
        POST /users (plain create) 1
        PATCH /users/{id} 1
        POST /groups with 20 members@odata.bind ~21

    At the default 20 items/sec, plain creates put ~20 writes/sec on the
    tenant; group creates with 20 bound members put ~420 writes/sec on it.

    The trap: heavy-write batches look fine at first. Graph's write throttle
    is a sliding budget, not an instant rate check -- a burst allowance
    absorbs the early chunks, then sustained throttle waves begin. Observed
    on a live ~100k-object tenant: 57,000 plain user creates ran at
    20 items/sec for 48 minutes with zero visible throttling, while group
    creates with 20-member binds at the same item rate ran clean for several
    thousand items and then drew 429 waves with multi-minute Retry-After
    backoff.

    Adaptive pacing recovers on its own (rates halve on 429, climb back on
    clean chunks, restore fully after five clean minutes) and no items are
    lost -- but recovery time is wall-clock time. For compound items, set
    the rate for the write cost up front:

        # Starting point: divide the default budget by writes-per-item
        # e.g. ~21-write group creates:
        Set-MgxOption -BatchItemsPerSecond 2

    Then let adaptive pacing find the tenant's real ceiling from below,
    instead of starting above it and paying for the discovery in Retry-After
    waits. Run with -Verbose to watch the rate adjustments.

POST SAFETY
    Non-idempotent methods (POST) only retry on 429 -- not on 5xx. A 500 on
    POST may mean the request was partially processed; blindly retrying could
    create duplicates.

LARGE TENANT CONFIGURATION
    Default settings are tuned for tenants up to ~10k objects. Larger tenants
    should adjust timeouts, rate limits, and batch pacing.

    Observed throughput (v1.0.1, live tenant):

        Operation Objects Throughput Notes
        --------- ------- ---------- -----
        User creation (batch POST) 25,000 20 items/sec Zero 429s with default pacing
        User enumerate (-All) 47,000 2,653/sec Streaming pagination
        Batch GET Mixed 107/sec Default settings

    50k+ tenants (read-heavy):

        Set-MgxOption -TotalTimeoutSeconds 600 `
                      -AttemptTimeoutSeconds 60 `
                      -RateLimitBurst 300 `
                      -RateLimitQueueLimit 2000

        TotalTimeoutSeconds 300 -> 600 Full enumeration takes > 5 min
        AttemptTimeoutSeconds 30 -> 60 Large pages can exceed 30s
        RateLimitBurst 200 -> 300 Absorbs pagination spikes
        RateLimitQueueLimit 500 -> 2,000 Fan-out queues more requests

    100k+ write operations:

        Set-MgxOption -BatchItemsPerSecond 15 `
                      -TotalTimeoutSeconds 3600 `
                      -AttemptTimeoutSeconds 180

        BatchItemsPerSecond 20 -> 15 Stay under write throttle
        TotalTimeoutSeconds 300 -> 3,600 100k writes takes ~110 min
        AttemptTimeoutSeconds 30 -> 180 Batch POST slows under load

SEE ALSO
    Set-MgxOption
    Get-MgxOption
    Get-MgxTelemetry
    about_Mgx