Skip to content

Commit 2145eb5

Browse files
feat(mattermost): add retry logic and timeout handling for DM channel creation (openclaw#42398)
Merged via squash. Prepared head SHA: 3db47be Co-authored-by: JonathanJing <[email protected]> Co-authored-by: mukhtharcm <[email protected]> Reviewed-by: @mukhtharcm
1 parent 7b61b02 commit 2145eb5

File tree

8 files changed

+1005
-13
lines changed

8 files changed

+1005
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ Docs: https://docs.openclaw.ai
133133
- macOS/launch at login: stop emitting `KeepAlive` for the desktop app launch agent so OpenClaw no longer relaunches immediately after a manual quit while launch at login remains enabled. (#40213) Thanks @stablegenius49.
134134
- ACP/gateway startup: use direct Telegram and Discord startup/status helpers instead of routing probes through the plugin runtime, and prepend the selected daemon Node bin dir to service PATH so plugin-local installs can still find `npm` and `pnpm`.
135135
- ACP/configured bindings: reinitialize configured ACP sessions that are stuck in `error` state instead of reusing the failed runtime.
136+
- Mattermost/DM send: retry transient direct-channel creation failures for DM deliveries, with configurable backoff and per-request timeout. (#42398) Thanks @JonathanJing.
136137

137138
## 2026.3.13
138139

docs/channels/mattermost.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,35 @@ OpenClaw resolves them **user-first**:
191191

192192
If you need deterministic behavior, always use the explicit prefixes (`user:<id>` / `channel:<id>`).
193193

194+
## DM channel retry
195+
196+
When OpenClaw sends to a Mattermost DM target and needs to resolve the direct channel first, it
197+
retries transient direct-channel creation failures by default.
198+
199+
Use `channels.mattermost.dmChannelRetry` to tune that behavior globally for the Mattermost plugin,
200+
or `channels.mattermost.accounts.<id>.dmChannelRetry` for one account.
201+
202+
```json5
203+
{
204+
channels: {
205+
mattermost: {
206+
dmChannelRetry: {
207+
maxRetries: 3,
208+
initialDelayMs: 1000,
209+
maxDelayMs: 10000,
210+
timeoutMs: 30000,
211+
},
212+
},
213+
},
214+
}
215+
```
216+
217+
Notes:
218+
219+
- This applies only to DM channel creation (`/api/v4/channels/direct`), not every Mattermost API call.
220+
- Retries apply to transient failures such as rate limits, 5xx responses, and network or timeout errors.
221+
- 4xx client errors other than `429` are treated as permanent and are not retried.
222+
194223
## Reactions (message tool)
195224

196225
- Use `message action=react` with `channel=mattermost`.

extensions/mattermost/src/config-schema.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,32 @@ import { z } from "zod";
99
import { requireChannelOpenAllowFrom } from "../../shared/config-schema-helpers.js";
1010
import { buildSecretInputSchema } from "./secret-input.js";
1111

12+
const DmChannelRetrySchema = z
13+
.object({
14+
/** Maximum number of retry attempts for DM channel creation (default: 3) */
15+
maxRetries: z.number().int().min(0).max(10).optional(),
16+
/** Initial delay in milliseconds before first retry (default: 1000) */
17+
initialDelayMs: z.number().int().min(100).max(60000).optional(),
18+
/** Maximum delay in milliseconds between retries (default: 10000) */
19+
maxDelayMs: z.number().int().min(1000).max(60000).optional(),
20+
/** Timeout for each individual DM channel creation request in milliseconds (default: 30000) */
21+
timeoutMs: z.number().int().min(5000).max(120000).optional(),
22+
})
23+
.strict()
24+
.refine(
25+
(data) => {
26+
if (data.initialDelayMs !== undefined && data.maxDelayMs !== undefined) {
27+
return data.initialDelayMs <= data.maxDelayMs;
28+
}
29+
return true;
30+
},
31+
{
32+
message: "initialDelayMs must be less than or equal to maxDelayMs",
33+
path: ["initialDelayMs"],
34+
},
35+
)
36+
.optional();
37+
1238
const MattermostSlashCommandsSchema = z
1339
.object({
1440
/** Enable native slash commands. "auto" resolves to false (opt-in). */
@@ -58,6 +84,8 @@ const MattermostAccountSchemaBase = z
5884
allowedSourceIps: z.array(z.string()).optional(),
5985
})
6086
.optional(),
87+
/** Retry configuration for DM channel creation */
88+
dmChannelRetry: DmChannelRetrySchema,
6189
})
6290
.strict();
6391

0 commit comments

Comments
 (0)