Skip to content

Commit 64e7865

Browse files
author
Tristan Lee
authored
Merge pull request #107 from edgio-docs/v7-waiting-room-revert
Revert to Upstash waiting room example
2 parents 376956e + 802c694 commit 64e7865

File tree

13 files changed

+237
-455
lines changed

13 files changed

+237
-455
lines changed

examples/v7-edge-functions/edgio.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// This file was automatically added by edgio init.
22
// You should commit this file to source control.
33
// Learn more about this file at https://docs.edg.io/guides/edgio_config
4+
require('dotenv').config();
5+
46
module.exports = {
57
connector: '@edgio/next',
68

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import createFetchForOrigin from '../../../utils/createFetchForOrigin';
2+
import {
3+
getCookiesFromRequest,
4+
setCookieToResponse,
5+
} from '../../../utils/cookies';
6+
import { setEnvFromContext } from '../../../utils/polyfills/process.env';
7+
import '../../../utils/polyfills/URL';
8+
import waitingPage from './waiting-room-capacity.html';
9+
import landingPage from './waiting-room-landing.html';
10+
11+
// Constants
12+
const COOKIE_NAME_ID = '__booking_id';
13+
const COOKIE_NAME_TIME = '__booking_last_update_time';
14+
const TOTAL_ACTIVE_USERS = 2;
15+
const SESSION_DURATION_SECONDS = 15;
16+
17+
// Setup fetch function for Upstash
18+
const fetch = createFetchForOrigin('upstash');
19+
20+
/**
21+
* Main handler for the edge request.
22+
*/
23+
export async function handleHttpRequest(request, context) {
24+
let resp;
25+
26+
// Set context environment variables to process.env
27+
setEnvFromContext(context);
28+
29+
const cookies = getCookiesFromRequest(request);
30+
31+
// Get user ID from cookie or generate a new one
32+
const userId = cookies[COOKIE_NAME_ID] ?? generateId();
33+
34+
// Get the current number of active sessions and the active user
35+
const size = await getRecordCount();
36+
const isActiveUser = (await getRecord(userId)) === '1';
37+
38+
console.log('Current number of active sessions: ', size);
39+
40+
// Check capacity
41+
if (size < TOTAL_ACTIVE_USERS || isActiveUser) {
42+
resp = await getDefaultResponse(request, userId);
43+
} else {
44+
resp = await getWaitingRoomResponse();
45+
}
46+
47+
return resp;
48+
}
49+
50+
/**
51+
* Generate a random ID
52+
*/
53+
function generateId(len = 10) {
54+
return Array.from({ length: len }, () =>
55+
((Math.random() * 36) | 0).toString(36)
56+
).join('');
57+
}
58+
59+
/**
60+
* Handle the default response.
61+
*/
62+
async function getDefaultResponse(request, userId) {
63+
const response = new Response(
64+
landingPage({
65+
domain: getDomainFromRequest(request),
66+
maxUsers: TOTAL_ACTIVE_USERS,
67+
sessionDuration: SESSION_DURATION_SECONDS,
68+
})
69+
);
70+
response.headers.set('content-type', 'text/html;charset=UTF-8');
71+
72+
const cookies = getCookiesFromRequest(request);
73+
const now = Date.now();
74+
const lastUpdate = cookies[COOKIE_NAME_TIME];
75+
let lastUpdateTime = 0;
76+
77+
if (lastUpdate) {
78+
lastUpdateTime = parseInt(lastUpdate);
79+
}
80+
81+
const diff = now - lastUpdateTime;
82+
const updateInterval = (SESSION_DURATION_SECONDS * 1000) / 2;
83+
if (diff > updateInterval) {
84+
await setExpiryRecord(userId, '1', SESSION_DURATION_SECONDS);
85+
setCookieToResponse(response, [[COOKIE_NAME_TIME, now.toString()]]);
86+
}
87+
88+
setCookieToResponse(response, [[COOKIE_NAME_ID, userId]]);
89+
return response;
90+
}
91+
92+
/**
93+
* Send a REST request to Upstash.
94+
*/
95+
async function sendUpstashRequest(cmd) {
96+
cmd = Array.isArray(cmd) ? cmd.join('/') : cmd;
97+
98+
return (
99+
await fetch(`${process.env.UPSTASH_REDIS_REST_URL}`, {
100+
method: 'POST',
101+
body: JSON.stringify(cmd.split('/')),
102+
headers: {
103+
Authorization: `Bearer ${process.env.UPSTASH_REDIS_REST_TOKEN}`,
104+
},
105+
})
106+
).json();
107+
}
108+
109+
/**
110+
* Get the current number of records.
111+
*/
112+
async function getRecordCount() {
113+
const data = await sendUpstashRequest('DBSIZE');
114+
return data.result;
115+
}
116+
117+
/**
118+
* Fetch a record from Upstash by key.
119+
*/
120+
async function getRecord(key) {
121+
const data = await sendUpstashRequest(['GET', key]);
122+
return data.result;
123+
}
124+
125+
/**
126+
* Set a record with an expiry time in Upstash.
127+
*/
128+
async function setExpiryRecord(key, value, seconds) {
129+
return sendUpstashRequest(['SET', key, value, 'EX', seconds]);
130+
}
131+
132+
/**
133+
* Response for the waiting room.
134+
*/
135+
async function getWaitingRoomResponse() {
136+
const response = new Response(waitingPage());
137+
response.headers.set('content-type', 'text/html;charset=UTF-8');
138+
return response;
139+
}
140+
141+
function getDomainFromRequest(request) {
142+
const url = new URL(request.url);
143+
return url.origin;
144+
}

examples/v7-edge-functions/functions/waiting-room/waiting-room-capacity.html.js renamed to examples/v7-edge-functions/functions/database/upstash/waiting-room-capacity.html.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const template = ({ queuePosition }) => `
1+
const template = () => `
22
<!DOCTYPE html>
33
<html lang="en">
44
@@ -70,10 +70,10 @@ const template = ({ queuePosition }) => `
7070
<div class="loader"></div>
7171
<h1>Almost There!</h1>
7272
<p>Our site is currently at full capacity. Thanks for your patience.</p>
73-
<p>You are number <strong>${queuePosition}</strong> in line.</p>
7473
<p>You'll be redirected shortly. Please do not close your browser.</p>
7574
</div>
7675
</body>
76+
7777
</html>
7878
`;
7979

examples/v7-edge-functions/functions/waiting-room/waiting-room-landing.html.js renamed to examples/v7-edge-functions/functions/database/upstash/waiting-room-landing.html.js

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const template = ({ requestUrl }) => `
1+
const template = ({ domain, maxUsers, sessionDuration }) => `
22
<!DOCTYPE html>
33
<html lang="en">
44
@@ -91,7 +91,7 @@ const template = ({ requestUrl }) => `
9191
}
9292
9393
function keepSessionAlive() {
94-
fetch('${requestUrl}/ping');
94+
fetch(window.location.origin + '/example/upstash-database');
9595
}
9696
9797
// Set interval to keep session alive every 15 seconds
@@ -101,26 +101,24 @@ const template = ({ requestUrl }) => `
101101
102102
<body>
103103
<div class='container'>
104-
<h1>Welcome to the Waiting Room Demo</h1>
105-
<Here>This demo showcases an effective way to manage website traffic during high-volume periods. When the site is at full capacity, visitors are temporarily placed in a waiting room, ensuring a smooth user experience. Here's how it works:</p>
106-
107-
<p>
108-
If you see this page, you have established a session as an active user since the session limit has not been reached.
109-
</p>
110-
<p>
111-
<strong>To simulate creating new sessions, issue the following command:</strong>
112-
<div class="code-block">for i in {1..5}; do curl ${requestUrl}; done</div>
113-
<button class="copy-btn" onclick="copyCodeToClipboard()">Copy Code</button>
114-
</p>
115-
<p>
116-
<strong>To start a new session which is queued,</strong> follow these instructions:
117-
<p>Open the link in a new private/incognito window: <a href="${requestUrl}" target="_blank">Start New Session</a>. This will attempt to establish a new session, which will be queued if the active session limit is reached.</p>
118-
</p>
119-
120-
<p>Dive into the code to see how it works.</p>
121-
<p><a href="https://github.com/edgio-docs/edgio-v7-edge-functions-example" target="_blank">View the demo code on GitHub</a></p>
122-
</div>
123-
104+
<h1>Welcome to the Waiting Room Demo</h1>
105+
<p>
106+
This demo showcases an effective way to manage website traffic during high-volume periods.
107+
When the site is at full capacity, visitors are temporarily placed in a waiting room, ensuring a smooth user experience.
108+
</p>
109+
<p>
110+
This is configured for a maximum of ${maxUsers} active sessions, with each session lasting ${sessionDuration} seconds.
111+
</p>
112+
<p>
113+
Experience this firsthand by opening <a href="${domain}/example/upstash-database">this link</a> in multiple incognito/private browser sessions.
114+
Once the site is at full capacity (2 active sessions), you will be placed in a waiting room until a spot opens up.
115+
</p>
116+
<p>Optionally, issue the <pre>curl</pre> command below to make multiple requests:</p>
117+
<div class="code-block">curl ${domain}/example/upstash-database</div>
118+
<button class="copy-btn" onclick="copyCodeToClipboard()">Copy Code</button>
119+
<p>Dive into the code to see how it works.</p>
120+
<p><a href="https://github.com/edgio-docs/edgio-v7-edge-functions-example" target="_blank">View the demo code on GitHub</a></p>
121+
</div>
124122
</body>
125123
126124
</html>

examples/v7-edge-functions/functions/general/sample-html-page.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ export async function handleHttpRequest(request, context) {
164164
<p>Transactional queries with a PlanetScale database.</p>
165165
</li>
166166
<li>
167-
<h4>Waiting Room using PlanetScale (<a href="/example/waiting-room">View Example</a>)</h4>
168-
<p>A waiting room example using PlanetScale for session tracking.</p>
167+
<h4>Upstash Database (<a href="/example/upstash-database">View Example</a>)</h4>
168+
<p>A waiting room example using Upstash + Redis.</p>
169169
</li>
170170
</ul>
171171
</section>

examples/v7-edge-functions/functions/waiting-room/constants.js

Lines changed: 0 additions & 77 deletions
This file was deleted.

examples/v7-edge-functions/functions/waiting-room/index.js

Lines changed: 0 additions & 78 deletions
This file was deleted.

0 commit comments

Comments
 (0)