mirror of
https://github.com/openai/codex.git
synced 2026-04-28 10:21:06 +03:00
128 lines
4.1 KiB
Markdown
128 lines
4.1 KiB
Markdown
**DOs**
|
||
|
||
- **Use one-liner mutex ops**: Acquire the lock, do the operation, and let the guard drop immediately.
|
||
```rust
|
||
running_requests_id_to_codex_uuid
|
||
.lock()
|
||
.await
|
||
.insert(request_id.clone(), session_id);
|
||
|
||
// ...
|
||
|
||
running_requests_id_to_codex_uuid
|
||
.lock()
|
||
.await
|
||
.remove(&request_id);
|
||
```
|
||
|
||
- **Handle error events decisively**: On `EventMsg::Error`, return a response, unregister, and break the loop.
|
||
```rust
|
||
match event {
|
||
EventMsg::Error(err) => {
|
||
outgoing
|
||
.send_response(request_id.clone(), serde_json::json!({ "error": err.message }))
|
||
.await;
|
||
running_requests_id_to_codex_uuid.lock().await.remove(&request_id);
|
||
break;
|
||
}
|
||
_ => { /* ... */ }
|
||
}
|
||
```
|
||
|
||
- **Make notifications truly async**: If the handler awaits, mark it `async` and await at the call site.
|
||
```rust
|
||
// lib.rs
|
||
match msg {
|
||
JSONRPCMessage::Notification(n) => processor.process_notification(n).await,
|
||
_ => { /* ... */ }
|
||
}
|
||
|
||
// message_processor.rs
|
||
pub(crate) async fn process_notification(&mut self, n: JSONRPCNotification) { /* ... */ }
|
||
```
|
||
|
||
- **Minimize lock scope and avoid nested locks**: Read what you need, drop the guard, then lock the next map.
|
||
```rust
|
||
let session_id = {
|
||
let g = self.running_requests_id_to_codex_uuid.lock().await;
|
||
match g.get(&request_id).copied() { Some(id) => id, None => return }
|
||
};
|
||
|
||
let codex = {
|
||
let g = self.session_map.lock().await;
|
||
match g.get(&session_id).cloned() { Some(c) => c, None => return }
|
||
};
|
||
```
|
||
|
||
- **Defer derived data until used**: Only compute `request_id_string` where you actually need it.
|
||
```rust
|
||
let maybe_id = self.running_requests_id_to_codex_uuid.lock().await.get(&request_id).copied();
|
||
if maybe_id.is_none() {
|
||
let request_id_string = match &request_id {
|
||
RequestId::String(s) => s.clone(),
|
||
RequestId::Integer(i) => i.to_string(),
|
||
};
|
||
tracing::warn!("Session not found for request_id: {request_id_string}");
|
||
return;
|
||
}
|
||
```
|
||
|
||
- **Write precise, portable tests**: Assert JSON-RPC errors explicitly and make blocking commands cross‑platform.
|
||
```rust
|
||
// Match JSON-RPC error
|
||
match mcp_process.read_jsonrpc_message().await? {
|
||
JSONRPCMessage::Error(e) if e.id == RequestId::Integer(codex_request_id) => { /* ok */ }
|
||
other => anyhow::bail!("unexpected message: {other:?}"),
|
||
}
|
||
|
||
// Cross-platform blocking command
|
||
#[cfg(target_os = "windows")]
|
||
let shell_command = vec![
|
||
"powershell".to_string(), "-Command".to_string(), "Start-Sleep -Seconds 60".to_string()
|
||
];
|
||
#[cfg(not(target_os = "windows"))]
|
||
let shell_command = vec!["sleep".to_string(), "60".to_string()];
|
||
```
|
||
|
||
**DON’Ts**
|
||
|
||
- **Don’t hold locks longer than necessary**: Avoid temporary guard variables and extra braces that extend lifetimes.
|
||
```rust
|
||
// ❌ Holds the lock longer than needed
|
||
let mut guard = running.lock().await;
|
||
guard.insert(request_id.clone(), session_id);
|
||
// guard lives until end of scope
|
||
```
|
||
|
||
- **Don’t ignore cleanup on all exit paths**: Always unregister request IDs on success, error, and submit failures.
|
||
```rust
|
||
// ❌ Missing cleanup on error
|
||
if let Err(e) = codex.submit_with_id(submission).await {
|
||
tracing::error!("submit failed: {e}");
|
||
// running_requests_id_to_codex_uuid.remove(...) is missing
|
||
}
|
||
```
|
||
|
||
- **Don’t treat MCP errors as “responses”**: Don’t assert on `JSONRPCResponse` with null/embedded error; match `JSONRPCMessage::Error`.
|
||
```rust
|
||
// ❌ Fragile: assumes error tunneled as a response payload
|
||
let JSONRPCMessage::Response(r) = msg else { /* ... */ };
|
||
assert!(r.result.get("error").is_some());
|
||
```
|
||
|
||
- **Don’t precompute derived strings you may not use**: Compute `request_id_string` only in the branches that need it.
|
||
```rust
|
||
// ❌ Work done upfront even if early-return
|
||
let request_id_string = match &request_id { /* ... */ };
|
||
// early return before using request_id_string
|
||
```
|
||
|
||
- **Don’t blanket-allow dead code/imports**: Prefer targeted allowances or remove unused helpers.
|
||
```rust
|
||
// ❌ Blanket allow across a module
|
||
#![allow(dead_code, unused_imports)]
|
||
|
||
// ✅ Narrow allowance for a single helper used by some tests
|
||
#[allow(dead_code)]
|
||
async fn read_stream_until_error(/* ... */) { /* ... */ }
|
||
``` |