Add realtime and storage specs

This commit is contained in:
Terry Sutton committed 2022-12-07 21:09:56 -03:30
1 parent 927a002817
commit c2429a6fb1
5 files changed
+107 -10

No files matched your search

-6
View File
@@ -1,6 +0,0 @@
---
id: release-notes
title: Release Notes
---
All release notes can be found in the [GitHub Releases page](https://github.com/supabase/cli/releases).
+57
View File
@@ -0,0 +1,57 @@
---
slug: /
sidebar_position: 1
id: realtime
title: Supabase Realtime Server
sidebar_label: Supabase Realtime Server
---
Supabase Realtime is a server built with Elixir using the [Phoenix Framework](https://www.phoenixframework.org) that allows you to listen to changes in your PostgreSQL database via logical replication and then broadcast those changes via WebSockets.
There are two versions of this server: `Realtime` and `Realtime RLS`.
`Realtime` server works by:
1. listening to PostgreSQL's replication functionality (using PostgreSQL's logical decoding)
2. converting the byte stream into JSON
3. broadcasting to all connected clients over WebSockets
`Realtime RLS` server works by:
1. polling PostgreSQL's replication functionality (using PostgreSQL's logical decoding and [wal2json](https://github.com/eulerto/wal2json) output plugin)
2. passing database changes to a [Write Ahead Log Realtime Unified Security (WALRUS)](https://github.com/supabase/walrus) PostgresSQL function and receiving a list of authorized subscribers depending on Row Level Security (RLS) policies
3. converting the changes into JSON
4. broadcasting to authorized subscribers over WebSockets
## Why not just use PostgreSQL's `NOTIFY`?
A few reasons:
1. You don't have to set up triggers on every table.
2. `NOTIFY` has a payload limit of 8000 bytes and will fail for anything larger. The usual solution is to send an ID and then fetch the record, but that's heavy on the database.
3. `Realtime` server consumes two connections to the database, then you can connect many clients to this server. Easier on your database, and to scale up you just add additional `Realtime` servers.
## Benefits
1. The beauty of listening to the replication functionality is that you can make changes to your database from anywhere - your API, directly in the DB, via a console, etc. - and you will still receive the changes via WebSockets.
2. Decoupling. For example, if you want to send a new slack message every time someone makes a new purchase you might build that functionality directly into your API. This allows you to decouple your async functionality from your API.
3. This is built with Phoenix, an [extremely scalable Elixir framework](https://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections).
## Does this server guarantee delivery of every data change?
Not yet! Due to the following limitations:
1. Postgres database runs out of disk space due to Write-Ahead Logging (WAL) buildup, which can crash the database and prevent Realtime server from receiving and broadcasting changes. This can be mitigated in the Realtime RLS version of this server by setting the Postgres config `max_slot_wal_keep_size` to a reasonable size.
2. Realtime server can crash due to a larger replication lag than available memory, forcing the creation of a new replication slot and resetting replication to read from the latest WAL data.
3. When Realtime server falls too far behind for any reason, for example disconnecting from database as WAL continues to build up, then database can delete WAL segments the server still needs to read from, for example after reconnecting.
## Client libraries
- [JavaScript](https://github.com/supabase/realtime-js)
- [Dart](https://github.com/supabase/realtime-dart)
## Additional Links
- [Source Code](https://github.com/supabase/realtime)
- [Known bugs and issues](https://github.com/supabase/realtime/issues)
- [Realtime Guides](https://supabase.com/docs/guides/realtime)
+1 -1
View File
@@ -176,7 +176,7 @@ export default function Config(props) {
export async function getStaticProps({ params }: { params: { slug: string[] } }) {
// an array of ids of the intro sections for this library
const introPages = ['cli', 'release-notes']
const introPages = ['cli']
const specPpages = cliSpec.commands
const pages = [...introPages, ...specPpages]
+47 -1
View File
@@ -1,3 +1,9 @@
import fs from 'fs'
import matter from 'gray-matter'
import components from '~/components/index'
import { MDXRemote } from 'next-mdx-remote'
import { serialize } from 'next-mdx-remote/serialize'
// @ts-expect-error
import specFile from '~/../../spec/realtime_v0_config.yaml' assert { type: 'yml' }
import { Parameter } from '~/lib/refGenerator/refTypes'
@@ -7,7 +13,7 @@ import ReactMarkdown from 'react-markdown'
// Parameters are grouped on the page by tag
const TAGS = ['general', 'database']
export default function Config() {
export default function Config(props) {
return (
<div>
<div className="flex my-16">
@@ -15,6 +21,13 @@ export default function Config() {
<h1 className="text-4xl mb-16">{specFile.info.title} Configuration</h1>
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
<div>
<div>
{props.docs
.filter((doc) => doc.introPage)
.map((item) => (
<MDXRemote {...item.content} components={components} />
))}
</div>
{TAGS.map((tag) =>
specFile.parameters
.filter((param: Parameter) => param.tags[0] === tag)
@@ -67,3 +80,36 @@ export default function Config() {
</div>
)
}
export async function getServerSideProps() {
// an array of ids of the intro sections for this library
const introPages = ['realtime']
const pages = [...introPages]
// Grab custom markdown intro page files
const allMarkdownDocs = await Promise.all(
pages.map(async (x: any, i) => {
const pathName = `docs/ref/realtime/${x}.mdx`
const markdownExists = fs.existsSync(pathName)
const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : ''
const { data, content } = matter(fileContents)
return {
id: x,
title: x,
// ...content,
meta: data,
introPage: introPages.includes(x),
content: content ? await serialize(content || '') : null,
}
})
)
return {
props: {
docs: allMarkdownDocs,
},
}
}
+2 -2
View File
@@ -2,9 +2,9 @@ configspec: '001'
# This section outlines the general information for the tool.
info:
id: 'storage' # {string} A unique ID for this tool.
id: 'realtime' # {string} A unique ID for this tool.
version: 'next' # {string} The current version number of the tool.
title: 'Storage' # {string} A readable name.
title: 'Realtime' # {string} A readable name.
source: 'https://github.com/supabase/realtime' # {string} Where developers can find the source code.
bugs: 'https://github.com/supabase/realtime/issues' # {string} Where developers can file bugs.
spec: 'https://github.com/supabase/supabase/blob/master/spec/realtime_v0_config.yml' # {string} Where developers can find this spec (to link directly in the docs).