Em loja, a internet cai. Um caixa que depende do servidor para fechar a venda para junto, com fila de
cliente na frente. E a falha mais cara nem é parar: é cobrar duas vezes quando a conexão volta e a mesma
venda é enviada de novo.
O caminho de uma venda
O caixa fecha a vendanada nesse passo depende da rede
A venda é gravada em disco primeirodiário só de acréscimo, com fsync, por comandos em Rust
Ela entra na fila de saídaum selo mostra ao operador o que ainda não subiu
Um agente envia a cada 90 segundosquando a rede volta, na ordem em que as vendas aconteceram
O servidor grava pela mesma função da venda onlineuma regra de venda só, para os dois caminhos
Quatro decisões
1. Disco antes da rede
A venda só existe depois de escrita e confirmada em disco. Se o computador desligar no meio, ela está lá
quando ele voltar. O catálogo de produtos também fica no caixa, para dar para vender sem consultar o servidor.
2. Retomada que não duplica
A fila guarda o número oficial que o servidor deu à venda e os itens que já foram gravados. Antes de fechar
de novo, o caixa confere se a venda já foi finalizada; sem isso, o pagamento entraria duas vezes.
3. Uma função de gravação só
A gravação da venda saiu das rotas e virou um serviço compartilhado: a venda online e a que chega pela fila
passam pelo mesmo código. O arquivo de rotas do PDV encolheu cerca de 240 linhas.
4. O servidor escolhe o caminho
O caixa pergunta ao servidor qual caminho de sincronização usar. Com isso, ligar ou desligar o robô do
servidor muda o comportamento de todos os caixas sem publicar uma versão nova do app.
O bug que o teste pegou
No Sequelize, um INSERT devolve [insertId, affectedRows]. Lido do jeito errado,
toda venda nova respondia "duplicada" e nunca entraria na fila. O teste pegou antes da publicação.
O que ainda falta
A busca de produtos do caixa offline devolve no máximo 20 resultados por consulta; para lojas com catálogo
grande, a próxima etapa é uma busca local com índice.
Case study · Offline POS
The register that keeps going when the internet drops.
How the Develop point of sale keeps selling with no network and syncs later, without losing a
sale or charging it twice.
Role
Design and implementation, from the Rust command to the server route
In a store, the internet drops. A register that needs the server to close a sale stops with it, with a line
of customers waiting. And the most expensive failure is not stopping: it is charging twice when the connection
returns and the same sale is sent again.
The path of a sale
The register closes the salenothing in this step depends on the network
The sale is written to disk firstappend-only journal with fsync, through Rust commands
It joins the outbound queuea badge shows the operator what has not been uploaded yet
An agent sends every 90 secondswhen the network returns, in the order the sales happened
The server writes it through the same function as an online saleone set of sales rules for both paths
Four decisions
1. Disk before network
A sale only exists once it is written and confirmed on disk. If the computer shuts down halfway, it is there
when it comes back. The product catalog also lives on the register, so it can sell without asking the server.
2. A resume that does not duplicate
The queue keeps the official number the server gave the sale and the items already written. Before closing
again, the register checks whether the sale was already finalized; without that, the payment would be recorded twice.
3. One write function
Writing a sale moved out of the routes into a shared service: online sales and queued sales run through the
same code. The POS routes file shrank by about 240 lines.
4. The server picks the path
The register asks the server which sync path to use. So turning the server-side robot on or off changes the
behavior of every register without shipping a new app version.
The bug the test caught
In Sequelize, an INSERT returns [insertId, affectedRows]. Read the wrong way, every
new sale answered "duplicate" and would never enter the queue. The test caught it before release.
What is still missing
The offline register's product search returns at most 20 results per query; for stores with a large catalog,
the next step is a local indexed search.
Case · POS offline
La caja que no para cuando cae internet.
Cómo el punto de venta de Develop sigue vendiendo sin red y sincroniza después, sin perder ni
cobrar dos veces una venta.
Rol
Diseño e implementación, del comando en Rust a la ruta en el servidor
En la tienda, internet se cae. Una caja que depende del servidor para cerrar la venta se detiene con él, con
clientes esperando. Y la falla más cara ni es parar: es cobrar dos veces cuando vuelve la conexión y la misma
venta se envía de nuevo.
El camino de una venta
La caja cierra la ventanada en este paso depende de la red
La venta se graba primero en discodiario solo de adición, con fsync, por comandos en Rust
Entra en la cola de salidauna señal muestra al operador lo que aún no subió
Un agente envía cada 90 segundoscuando vuelve la red, en el orden en que ocurrieron las ventas
El servidor la graba con la misma función de la venta onlineuna sola regla de venta para los dos caminos
Cuatro decisiones
1. Disco antes que red
La venta solo existe después de escrita y confirmada en disco. Si la computadora se apaga a mitad, está ahí
cuando vuelve. El catálogo de productos también vive en la caja, para vender sin consultar al servidor.
2. Una reanudación que no duplica
La cola guarda el número oficial que el servidor le dio a la venta y los ítems ya grabados. Antes de cerrarla
otra vez, la caja confirma si la venta ya fue finalizada; sin eso, el pago entraría dos veces.
3. Una sola función de grabación
La grabación de la venta salió de las rutas y pasó a ser un servicio compartido: la venta online y la que llega
por la cola pasan por el mismo código. El archivo de rutas del POS se redujo en unas 240 líneas.
4. El servidor elige el camino
La caja le pregunta al servidor qué camino de sincronización usar. Así, encender o apagar el robot del servidor
cambia el comportamiento de todas las cajas sin publicar una versión nueva de la app.
El bug que atrapó la prueba
En Sequelize, un INSERT devuelve [insertId, affectedRows]. Leído de forma incorrecta,
toda venta nueva respondía "duplicada" y nunca entraría en la cola. La prueba lo atrapó antes de publicar.
Lo que todavía falta
La búsqueda de productos de la caja offline devuelve como máximo 20 resultados por consulta; para tiendas con
catálogo grande, el próximo paso es una búsqueda local con índice.