0
# Push Operations
1
2
Push mechanism for sending messages to channels with delivery status tracking and timeout handling, enabling reliable message delivery confirmation.
3
4
## Capabilities
5
6
### Push Constructor
7
8
Creates a new Push instance for sending messages with status tracking.
9
10
```typescript { .api }
11
/**
12
* Creates a new Push instance for sending messages with status tracking
13
* @param channel - Channel to send message through
14
* @param event - Event name for the message
15
* @param payload - Message payload object
16
* @param timeout - Timeout in milliseconds for the push operation
17
*/
18
constructor(channel: Channel, event: string, payload: object, timeout: number);
19
```
20
21
**Note:** Push instances are typically created through `channel.push()` rather than directly constructing them.
22
23
### Message Sending
24
25
Send and resend push messages.
26
27
```typescript { .api }
28
/**
29
* Send the push message
30
*/
31
send(): void;
32
33
/**
34
* Resend the push message with a new timeout
35
* @param timeout - New timeout value in milliseconds
36
*/
37
resend(timeout: number): void;
38
```
39
40
**Usage Example:**
41
42
```typescript
43
import { Channel, Socket } from "phoenix";
44
45
const socket = new Socket("/socket");
46
const channel = socket.channel("room:lobby");
47
48
// Create push through channel (recommended)
49
const push = channel.push("new_message", {
50
body: "Hello, Phoenix!",
51
user_id: 123
52
}, 5000);
53
54
// Send immediately (usually not needed as channel.push() sends automatically)
55
push.send();
56
57
// Resend with longer timeout if needed
58
push.resend(10000);
59
```
60
61
### Status Handling
62
63
Register callbacks for different push response statuses.
64
65
```typescript { .api }
66
/**
67
* Register callback for specific push status
68
* @param status - Push status to handle ("ok", "error", or "timeout")
69
* @param callback - Function to call when status is received
70
* @returns Push instance for chaining
71
*/
72
receive(status: PushStatus, callback: (response?: any) => any): this;
73
74
type PushStatus = "ok" | "error" | "timeout";
75
```
76
77
**Usage Example:**
78
79
```typescript
80
// Chain status handlers
81
channel.push("create_post", {
82
title: "My Post",
83
content: "Post content here..."
84
})
85
.receive("ok", (response) => {
86
console.log("Post created successfully:", response.post);
87
// Navigate to new post
88
window.location.href = `/posts/${response.post.id}`;
89
})
90
.receive("error", (errors) => {
91
console.error("Failed to create post:", errors);
92
// Show validation errors to user
93
displayErrors(errors);
94
})
95
.receive("timeout", () => {
96
console.warn("Post creation timed out");
97
// Show retry option to user
98
showRetryDialog();
99
});
100
```
101
102
## Advanced Usage Patterns
103
104
### Error Handling with Retry Logic
105
106
```typescript
107
function sendMessageWithRetry(channel: Channel, event: string, payload: object, maxRetries = 3) {
108
let attempts = 0;
109
110
function attempt(): Promise<any> {
111
return new Promise((resolve, reject) => {
112
attempts++;
113
114
channel.push(event, payload, 5000)
115
.receive("ok", resolve)
116
.receive("error", (errors) => {
117
if (attempts < maxRetries) {
118
console.log(`Attempt ${attempts} failed, retrying...`);
119
setTimeout(() => {
120
attempt().then(resolve).catch(reject);
121
}, 1000 * attempts); // Exponential backoff
122
} else {
123
reject(new Error(`Failed after ${maxRetries} attempts: ${JSON.stringify(errors)}`));
124
}
125
})
126
.receive("timeout", () => {
127
if (attempts < maxRetries) {
128
console.log(`Attempt ${attempts} timed out, retrying...`);
129
setTimeout(() => {
130
attempt().then(resolve).catch(reject);
131
}, 1000 * attempts);
132
} else {
133
reject(new Error(`Timed out after ${maxRetries} attempts`));
134
}
135
});
136
});
137
}
138
139
return attempt();
140
}
141
142
// Usage
143
sendMessageWithRetry(channel, "important_action", { data: "critical" })
144
.then(result => console.log("Success:", result))
145
.catch(error => console.error("Final failure:", error));
146
```
147
148
### Status-based Flow Control
149
150
```typescript
151
function handleFormSubmission(channel: Channel, formData: object) {
152
const submitButton = document.getElementById("submit-btn") as HTMLButtonElement;
153
const errorDiv = document.getElementById("errors") as HTMLDivElement;
154
const successDiv = document.getElementById("success") as HTMLDivElement;
155
156
// Disable submit button during request
157
submitButton.disabled = true;
158
submitButton.textContent = "Submitting...";
159
160
channel.push("form_submit", formData, 10000)
161
.receive("ok", (response) => {
162
// Success handling
163
successDiv.style.display = "block";
164
successDiv.textContent = "Form submitted successfully!";
165
errorDiv.style.display = "none";
166
167
// Reset form
168
(document.getElementById("form") as HTMLFormElement).reset();
169
})
170
.receive("error", (errors) => {
171
// Error handling
172
errorDiv.style.display = "block";
173
errorDiv.innerHTML = "";
174
175
// Display validation errors
176
Object.entries(errors).forEach(([field, messages]) => {
177
const errorItem = document.createElement("div");
178
errorItem.textContent = `${field}: ${(messages as string[]).join(", ")}`;
179
errorDiv.appendChild(errorItem);
180
});
181
182
successDiv.style.display = "none";
183
})
184
.receive("timeout", () => {
185
// Timeout handling
186
errorDiv.style.display = "block";
187
errorDiv.textContent = "Request timed out. Please try again.";
188
successDiv.style.display = "none";
189
});
190
191
// Always re-enable submit button
192
setTimeout(() => {
193
submitButton.disabled = false;
194
submitButton.textContent = "Submit";
195
}, 1000);
196
}
197
```
198
199
### Promise-based Push Wrapper
200
201
```typescript
202
function pushPromise(channel: Channel, event: string, payload: object, timeout = 5000): Promise<any> {
203
return new Promise((resolve, reject) => {
204
channel.push(event, payload, timeout)
205
.receive("ok", resolve)
206
.receive("error", reject)
207
.receive("timeout", () => reject(new Error("Push operation timed out")));
208
});
209
}
210
211
// Usage with async/await
212
async function createUser(channel: Channel, userData: object) {
213
try {
214
const response = await pushPromise(channel, "create_user", userData, 8000);
215
console.log("User created:", response.user);
216
return response.user;
217
} catch (error) {
218
console.error("Failed to create user:", error);
219
throw error;
220
}
221
}
222
```
223
224
### Batch Operations with Status Tracking
225
226
```typescript
227
async function batchOperations(channel: Channel, operations: Array<{event: string, payload: object}>) {
228
const results = [];
229
const errors = [];
230
231
for (const [index, operation] of operations.entries()) {
232
try {
233
const result = await new Promise((resolve, reject) => {
234
channel.push(operation.event, operation.payload, 5000)
235
.receive("ok", resolve)
236
.receive("error", reject)
237
.receive("timeout", () => reject(new Error("Timeout")));
238
});
239
240
results.push({ index, result });
241
} catch (error) {
242
errors.push({ index, error, operation });
243
}
244
}
245
246
return { results, errors };
247
}
248
249
// Usage
250
const operations = [
251
{ event: "create_post", payload: { title: "Post 1" } },
252
{ event: "create_post", payload: { title: "Post 2" } },
253
{ event: "update_user", payload: { name: "Updated Name" } }
254
];
255
256
batchOperations(channel, operations)
257
.then(({ results, errors }) => {
258
console.log(`Completed ${results.length} operations successfully`);
259
if (errors.length > 0) {
260
console.error(`${errors.length} operations failed:`, errors);
261
}
262
});
263
```
264
265
### Push Status Monitoring
266
267
```typescript
268
class PushMonitor {
269
private activePushes: Map<string, { push: Push, startTime: number }> = new Map();
270
271
track(id: string, channel: Channel, event: string, payload: object, timeout = 5000) {
272
const startTime = Date.now();
273
const push = channel.push(event, payload, timeout);
274
275
this.activePushes.set(id, { push, startTime });
276
277
push
278
.receive("ok", (response) => {
279
this.complete(id, "ok", response);
280
})
281
.receive("error", (errors) => {
282
this.complete(id, "error", errors);
283
})
284
.receive("timeout", () => {
285
this.complete(id, "timeout", null);
286
});
287
288
return push;
289
}
290
291
private complete(id: string, status: PushStatus, response: any) {
292
const entry = this.activePushes.get(id);
293
if (entry) {
294
const duration = Date.now() - entry.startTime;
295
console.log(`Push ${id} completed with status ${status} in ${duration}ms`);
296
this.activePushes.delete(id);
297
}
298
}
299
300
getActivePushes(): string[] {
301
return Array.from(this.activePushes.keys());
302
}
303
304
getActivePushCount(): number {
305
return this.activePushes.size;
306
}
307
}
308
309
// Usage
310
const monitor = new PushMonitor();
311
312
monitor.track("post-creation", channel, "create_post", {
313
title: "My New Post",
314
content: "Post content..."
315
});
316
317
console.log("Active pushes:", monitor.getActivePushCount());
318
```