Skip to content

Instantly share code, notes, and snippets.

@geecko86
Created July 2, 2019 14:29
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save geecko86/36d244cb4842276e55e0b5ffdca883aa to your computer and use it in GitHub Desktop.
Handmade load balancer for Cloudflare Workers
const europe = ["AMS", "ATH", "BCN", "BEG", "TXL", "BRU", "OTP", "BUD", "KIV", "CPH", "DUB", "DUS", "EDI", "FRA", "GVA", "GOT", "HAM", "HEL", "IST", "KBP", "LIS", "LHR", "LUX", "MAD", "MAN", "MRS", "MXP", "DME", "MUC", "LCA", "OSL", "CDG", "PRG", "KEF", "RIX", "FCO", "LED", "SOF", "ARN", "TLL", "SKG", "VIE", "VNO", "WAW", "ZAG", "ZRH"];
const africa = ["CAI", "CMN", "CPT", "DAR", "JIB", "DUR", "JNB", "LOS", "LAD", "MPM", "MBA", "MRU", "RUN", "KGL"];
const asia = ["BKK", "CEB", "CTU", "MAA", "CMB", "SZX", "FUO", "FOC", "CAN", "HGH", "HAN", "HNY", "SGN", "HKG", "HYD", "ISB", "TNA", "KHI", "KTM", "KUL", "LHE", "NAY", "LYA", "MFM", "MNL", "BOM", "NNG", "DEL", "KIX", "PNH", "TAO", "ICN", "SHA", "SHE", "SJW", "SIN", "SZV", "TPE", "TSN", "NRT", "ULN", "WUH", "WUX", "XIY", "EVN", "CGO", "CSX"];
const latinAmerica = ["ASU", "BOG", "EZE", "CWB", "FOR", "LIM", "MDE", "MEX", "PTY", "POA", "UIO", "GIG", "GRU", "SCL", "CUR"];
const middleEast = ["AMM", "BGW", "GYD", "BEY", "DOH", "DXB", "KWI", "BAH", "MCT", "ZDM", "RUH", "TLV"];
const northAmerica = ["IAD", "ATL", "BOS", "BUF", "YYC", "CLT", "ORD", "CMH", "DFW", "DEN", "DTW", "IAH", "IND", "JAX", "MCI", "LAS", "LAX", "MFE", "MEM", "MIA", "MSP", "MGM", "YUL", "BNA", "EWR", "ORF", "OMA", "PHX", "PIT", "PDX", "QRO", "RIC", "SMF", "SLC", "SAN", "SJC", "YXE", "SEA", "STL", "TPA", "YYZ", "YVR", "TLH", "YWG"];
const oceania = ["AKL", "BNE", "MEL", "PER", "SYD"]
const euroApi = "europe-west1-XXXXXX.cloudfunctions.net";
const usApi = "us-central1-XXXXXX.cloudfunctions.net";
const asiaApi = "asia-east2-XXXXXX.cloudfunctions.net";
addEventListener('fetch', event => {
// A promise is required
event.respondWith(eventHandler(event))
})
async function eventHandler(event){
let hostname = matchGeo(event.request.cf ? event.request.cf.colo : "BRU") // the "cf" object is not accessible in the Playground
return await fetch(genRequest(event.request, hostname)).then((response) => {
if (response.status < 400) // If OK or redirect
return response;
else throw new Error(response.status + " " + hostname);
}).catch(async (err) => {
// In case of issues, try another host
console.error(err);
return await fetch(genRequest(event.request, getBackupHost(hostname))).then((response) => {
console.log(response);
if (response.status < 400) // if OK or redirect
return response;
else throw new Error(response.status);
}).catch((err) => {
console.error(err)
return new Response(null, {status: 500}); // We're giving up
});
});
}
function matchGeo(colo) {
if (europe.includes(colo))
return euroApi;
else if (africa.includes(colo))
return euroApi;
else if (asia.includes(colo))
return asiaApi;
else if (latinAmerica.includes(colo))
return usApi;
else if (middleEast.includes(colo))
return euroApi;
else if (northAmerica.includes(colo))
return usApi;
else
return asiaApi;
}
function getBackupHost(hostname) {
switch(hostname){
case usApi:
return euroApi;
default:
return usApi;
}
}
function genRequest(request, hostname) {
let url = new URL(request.url)
url.hostname = hostname
return new Request(url, request)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment