Blog

Prémer Publica dues vegades ara publica només una

Tres peticions de publicació per a la mateixa app van arribar a la nostra API amb 84 mil·lisegons de diferència, i cadascuna va iniciar un desplegament complet d'aquella app. Es disputaven el mateix allotjament, diverses de les versions resultants van fallar perquè una altra ja hi havia arribat primer, i l'únic senyal visible van ser els correus de «la publicació ha fallat» —l'app en si va acabar bé. Ara, una publicació que arriba mentre una altra ja s'executa per a la mateixa app no inicia una segona construcció. La base de dades decideix quina petició guanya, i les altres reben la informació real: ja hi ha una publicació en curs.

Què va passar

Quan publiques una app a Mythex, l'API registra un desplegament per a ella i demana a l'orquestrador —el servei que executa les construccions— que la construeixi i la publiqui. La publicació pot començar des del botó Publica, des d'una altra pestanya del navegador, o des de l'agent quan li demanes que publiqui. Un doble clic, dues pestanyes, o una petició de l'agent que arriba dues vegades poden produir més d'una publicació per a la mateixa app gairebé al mateix moment.

En aquest cas, en van arribar tres en 84 ms. Cadascuna va executar un desplegament complet. A la plataforma d'allotjament, es van crear versions per a la mateixa app en el mateix segon, i tres d'elles van fallar perquè les altres ja estaven en curs. Una versió posterior es va encallar, i després l'app funcionava.

Això és el que la feia fàcil de passar per alt. L'usuari veia una sola app que funcionava. Les fallades només apareixien als correus d'error de versió.

Per què res no ho aturava

El codi de publicació sí que tenia un pas que mirava els desplegaments en curs del projecte. Però el que feia era marcar tots els desplegaments en curs com a fallits abans de començar —«substituït per una nova publicació». Estava pensat per netejar construccions que un procés caigut havia deixat a mig fer.

A la pràctica, una segona publicació que arribava enmig d'una construcció declarava morta la primera i començava la seva pròpia. Ambdues s'executaven fins al final contra la mateixa app. No hi havia cap bloqueig; hi havia un pas que, de manera activa, aclaria el camí per a una cursa.

N'hi havia un segon símptoma, més estrany, per a la primera publicació d'una app. Sense cap registre de desplegament per reutilitzar encara, dues primeres publicacions concurrents intentaven inserir-ne un. La base de dades té un índex únic sobre el nom d'enllaç de l'app (el seu slug, com la-teva-app a la-teva-app.mythex.ai), així que la segona inserció fallava. L'API ho traduïa com «aquest nom d'enllaç ja està agafat» —aconsellant a l'usuari que canviés el nom d'una app que, en aquell moment, s'estava publicant bé amb aquell nom.

L'arranjament: la reclamació és el bloqueig

Reclamar el registre de desplegament és ara una sola actualització condicional a la base de dades: agafa aquesta fila i marca-la com a construint només si ningú no la està publicant. Com que és una sola sentència, la base de dades resol les peticions que arriben dins del mateix mil·lisegon. Exactament una d'elles canvia la fila. Les altres veuen que no s'ha canviat cap fila, s'aturen, i mai no arriben a l'orquestrador.

Un bloqueig també necessita una sortida quan el seu titular mor. Si l'API es reiniciava enmig d'una publicació, la fila quedaria marcada com a «construint» per sempre i l'app no es podria publicar mai més. Així que una fila el propietari de la qual ha deixat d'enviar senyals de vida —la publicació en curs actualitza la fila cada 30 segons, i cinc minuts de silenci compten com a mort— es pot reclamar de nou. Aquest llindar ve del senyal de vida, no d'una suposició sobre quant dura una construcció. Construir un Dockerfile propi de l'usuari pot trigar molt de temps amb tota legitimitat, i una construcció lenta que continua enviant senyals de vida conserva la seva reclamació.

El pas que marcava com a fallits tots els desplegaments en curs ja no s'executa abans d'una publicació. Només s'eliminen les files que un procés mort ha deixat enrere.

Dir la veritat a qui perd

La petició que perd ara rep una resposta clara: publish_in_progress, juntament amb l'identificador del desplegament que s'està executant. Cada lloc que pot iniciar una publicació ho gestiona:

  • L'espai de treball segueix la construcció que ja s'està executant en lloc de mostrar un error per sobre.
  • L'agent rep la informació que una publicació d'aquesta app ja s'està executant i que ha d'esperar-la, en lloc de rebre la de que alguna cosa ha fallat —cosa que abans el podia portar a «arreglar» un Dockerfile i tornar a intentar-ho.
  • Una col·lisió de primera publicació sobre el nom d'enllaç es comprova: si la fila que té el nom és la publicació en curs del mateix projecte, la resposta és «ja s'està publicant», no «aquest nom ja està agafat». Una col·lisió real amb un altre projecte continua donant el missatge de canviar de nom.

Com ho hem comprovat

Hem escrit un script de reproducció que executa tres publicacions de la mateixa app alhora contra una base de dades real i un orquestrador de prova, i compta quants desplegaments demana a l'orquestrador. Cobreix una primera publicació i una republicació d'una app en línia. Abans de l'arranjament, en comptava dos. Després, un.

L'script també cobreix la sortida d'emergència: marca la fila de l'app com a construint sense senyal de vida durant deu minuts, torna a publicar, i comprova que la nova publicació reclama la fila i s'executa.

Les proves unitàries mantenen el bloqueig a les dues coses que un bloqueig ha de fer: de tres republicacions simultànies, exactament una passa i les altres dues reben la informació que hi ha una publicació en marxa; i una construcció el propietari de la qual ha mort es pot reclamar. Una altra prova comprova que un intent nou no arrossega el missatge d'error de l'intent anterior.

Què n'hem après

  • El codi de neteja pot ser una cursa disfressada. «Fallar tot el que està en curs i després començar» sembla higiene. Amb dos que el criden, és cadascun cancel·lant l'altre.
  • Deixa que la base de dades arbitri. Una lectura seguida d'una escriptura deixa un buit per a una altra petició. Una sola actualització condicional no.
  • Tot bloqueig necessita una caducitat lligada a la vida. Sense ella, una caiguda es converteix en una app encallada.
  • Els missatges d'error són instruccions. «Aquest nom ja està agafat» feia que la gent fes la cosa equivocada. El missatge correcte era més simple i cert.

Més sobre la publicació a la documentació: com publicar. I una correcció relacionada: la teva app publicada es manté en línia mentre la tornes a publicar.

Mythex · Pricing · Crea qualsevol cosa amb IA · Plantilles de llocs web i aplicacions · Mythex comparat · Glossari de creació d’aplicacions amb IA · Eines gratuïtes per crear aplicacions amb IA · English

English አማርኛ العربية Български বাংলা Bosanski Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)