- Martin Lambert

- Nov 22, 2021
- 4 min read
Updated: Nov 23, 2021
I’m CTO and co-founder of a startup called Ringaly, and a full stack developer. I chose Wix over frameworks like Angular or React because of the radically faster time-to-market offered by its drag-and-drop Editor, its library of pre-integrated components, and the Wix APIs I can access through Velo, which let me choose my own path by building on top of the basic Wix functionality. The best example of Velo’s ability to extend Wix was our requirement to speed up Wix database queries by a factor of 10x to support real-time routing of telephone calls. To see why that is so important, you need to understand the Ringaly application.
The business
Ringaly is not what you might expect from a Wix site. It’s a cloud telephony service that ensures families don’t miss phone calls about their loved ones - or a family phone number that works beyond the home. Families buy a phone number from Ringaly, add family cell phones to it as contacts and share it with school, after school, doctors, etc. When someone calls the Ringaly number it simultaneously rings all their family contacts and the first to answer gets the call. Other family contacts get a text saying who called and who answered. Simple!
The technical problem
So our Wix site is fundamentally capturing the routing information used by our cloud telephony provider (Twilio) to forward calls and texts to family members. It’s not complicated information - just a simple mapping between Ringaly phone numbers and associated family contacts (and their names so we can send texts saying “Call from school was answered by Mom”) so it’s easy to store in a custom Velo database collection.
The technical problem is that Twilio needs to access this routing information in real-time, as incoming phone calls are received. The Wix database is powerful, scalable and resilient but isn’t optimized for high-speed applications out of the box. A typical database query on a Wix collection can easily take 2 seconds or more. To be fair it doesn’t normally need to be super fast. It just needs to be as fast as typical page load times. But telephony applications are *very* sensitive to latency. Calls that ring interminably get dropped. So we needed to speed up Wix collection queries by 10 times, from >2 secs to a blistering sub-200ms.
The solution: integrating Wix with Redis
Fortunately, speeding up database queries is a common problem with a standard solution: placing a high-speed data cache in between the database (Wix) and the reader (Twilio) - see the graphic at the top of this article. The idea is that data from the slower database is automatically synchronised into the faster cache so the reader can get at it more quickly. The cache we used is Redis (via Twilio Sync), an amazingly quick millisecond-level state synchronization API which we use as our cache.
There are a few different caching patterns or strategies (see this neat summary) but we settled on a hybrid of two cooperating patterns:
Client-side inline read-through cache
Backend inline write-through cache
Client-side inline read-through cache
/**
* Get Ring using Redis to implement inline
* (read-through) cache
*/
async function getRing(label, context, twilioClient,
axios, inNumber) {
const ringDocName = 'ring-' + inNumber;
let ringDoc = await fetchSyncDoc(
context,
twilioClient,
ringDocName
);
console.log(
label,
ringDocName,
ringDoc ?
JSON.stringify(ringDoc.data) :
'cache miss'
);
if (!ringDoc) {
// Twilio overrides default Authorization header
// (so create our own)
let config = {
params: { inNumber: inNumber },
headers: {
'Ringaly-Authorization':
'Bearer ' + context.WIX_KEY
}
};
// Retrieve OUT numbers from Wix
const response = await axios.get(
context.WIX_RING_URL, config
);
const ringInfo = getRingInfo(response.data);
ringDoc = await createSyncDocWithRetry(
context,
twilioClient,
ringDocName,
ringInfo,
RING_TTL
);
}
if (ringDoc)
return ringDoc.data;
}Twilio code
When a phone call comes in to Twilio (the client) it first looks in Redis for the associated family contacts. If it can’t find them (known as a ‘cache miss’) it uses the Axios library to make a HTTPS request to Wix (handled by the Velo wix-http-functions API) to fetch the data from the Wix database (even though this is slow) and adds them to Redis for next time. Although slow for the initial query this is a useful safety net in case the other caching pattern hasn’t already populated the cache.
Backend inline write-through cache
/**
* Update Ring in database and cache
* @param {*} userInfo
* @param {Ring} ring - assume ring.outNumbers is
* in stringified format
* @returns {Promise<Ring>} updated Ring (with
* stringified outNumbers)
*/
export async function updateRing(userInfo, ring) {
let updatedRing = null;
try {
// FIXME FIXME wixData.update mutates
// its input item object,
// removing included multi-references and
// reverting included single references to Ids
// Workaround: use a shallow copy
// of the input object
let updateRing = Object.assign({}, ring);
updatedRing = await wixData.update(
constants.COLLECTION_RINGS,
updateRing,
{'suppressAuth': true}
);
const twilioSync = await getTwilioSync();
const ringDocName = prefix + ring.inNumber;
const ringInfo = getRingInfo(ring);
// Just in case, check whether
// ringDoc is already in cache
let syncDoc = await fetchSyncDoc(
userInfo,
twilioSync,
ringDocName
);
if (syncDoc)
await updateSyncDoc(
userInfo,
twilioSync,
ringDocName,
ringInfo,
RING_TTL
);
else
await createSyncDoc(
userInfo,
twilioSync,
ringDocName,
ringInfo,
RING_TTL
);
}
catch(error) {
logError(userInfo, label, 'updateRing', error);
throw error;
}
return updatedRing;
}Twilio code
Whenever call routing information is created or updated in the Wix database our Velo code updates both the database collection AND the cache. This keeps the cache ‘fresh’ and reduces (and potentially even eliminates) the possibility of client-side ‘cache misses’. The updateSyncDoc() and createSyncDoc() functions shown above call Redis APIs via an NPM module installed in the Velo backend.
Bottom line
The Velo wix-http-functions API allows third party applications (like Twilio, our cloud telephony provider) direct and secure access to the Wix database. In the opposite direction the fact that Velo is running on the extensible Node.js platform allows installation of third party NPM modules to directly access third party applications like Twilio from Wix (so we can make calls or send texts and cache information from the Wix database).
Ringaly is using Velo’s remarkable bidirectional extensibility to power a real-time family call-forwarding service and to speed up Wix database queries by 10x times! Wix gave us fast time to market and, thanks to Velo, we don't have to compromise on integrations or customization.
Learn more about Ringaly here.








Comments