Elido
6 Min. LesezeitEngineering

Auslieferung der Short.io-Migration: Paginierung pro Domain mit 150/Seite

Wie wir One-Click-Short.io-Importe für Elido entwickelt haben — das Paginierungsmodell pro Domain, die Regel für deaktivierte private Links und die schnellste unserer fünf Migrationsquellen.

Marius Voß
DevRel · edge infra
Pipeline-Diagramm: Short.io REST API links, die durch den Elido-Import-Worker in die Links-Tabelle fließt, mit einem Seitenbereich, der die numerischen Garantien des Workers auflistet (50k Limit, 30 Min. Budget, 150 pro Seite, Token nur im Arbeitsspeicher)

Die dritte Migrationsquelle in unserem Tier-3-Rollout wurde heute veröffentlicht. Fügen Sie einen Short.io API key ein, wählen Sie die Short.io-Quelldomain (z. B. example.short.gy), wählen Sie die Elido-Zieldomain und klicken Sie auf Start. Drei bis sechs Minuten später befindet sich jeder Link auf Ihrer Elido-Domain, wobei der Slug beibehalten wurde.

Dieser Beitrag ist der technische Bericht – was spezifisch für Short.io ist, was uns an deren REST API überrascht hat und warum wir uns entschieden haben, Jobs pro Domain statt Batches pro Konto anzubieten.

Pro Domain, nicht pro Konto#

Das Datenmodell von Short.io hat eine Besonderheit, die das gesamte UX des Launchers geprägt hat: Links sind unter Domains organisiert, und der /links endpoint paginiert pro Domain. Es gibt keinen Aufruf vom Typ „Gib mir jeden Link über alle Domains in diesem Konto hinweg“.

Wir haben einige Designs in Betracht gezogen:

  • A. Jede Domain serverseitig iterieren, dem Benutzer einen einzigen Job präsentieren. Schneller aus Sicht der Klick-Anzahl; schwieriger, den Fortschritt und die Wahl der Konfliktstrategie pro Domain darzustellen.
  • B. Ein Elido-Job pro Quelldomain. Langsamer bei den Klicks (der Benutzer führt N Jobs für N Domains aus), aber jeder Job hat einen klaren Vertrag: eine Quelldomain → eine Zieldomain → eine Konfliktstrategie.
  • C. Jede Domain auflisten, dem Benutzer eine Mehrfachauswahl ermöglichen, N Jobs serverseitig in die Warteschlange stellen.

Wir haben B veröffentlicht und C für die nächste Iteration des Rollout-Plans vorgesehen. Der Launcher fragt nach dem Hostnamen der Quelldomain als Textfeld (kein Dropdown – die /domains list von Short.io ist zwar günstig aufzurufen, fügt aber einen Roundtrip hinzu, und der Benutzer kennt seinen eigenen Domain-Hostnamen immer). Ein Job pro Domain, der nacheinander vom Dashboard aus in die Warteschlange gestellt wird.

Der Vorteil der Seitengröße#

Short.io paginiert standardmäßig mit 150 Links pro Aufruf – das ist die großzügigste unserer fünf Migrationsquellen. Zum Vergleich:

  • Bitly: 100 pro Seite
  • Rebrandly: 25 pro Seite
  • TinyURL: 100 pro Seite (Pro/Bulk)
  • Dub.co: 100 pro Seite
  • Short.io: 150 pro Seite

Eine Short.io-Domain mit 5.000 Links benötigt 34 Roundtrips. Ein Rebrandly-Konto mit 5.000 Links benötigt 200. Der Worker verbringt den Großteil seiner Laufzeit mit dem Warten auf HTTP-Antworten, daher ist dies von Bedeutung – Short.io ist empirisch die schnellste von uns unterstützte Migrationsquelle.

const shortioPageSize = 150

page := 1
for {
    resp, err := w.fetchPage(ctx, opts.Token, opts.DomainID, page)
    if err != nil { /* mark failed */ return }
    if len(resp.Links) == 0 { break }
    for _, link := range resp.Links { /* import */ }
    if !resp.HasMore { break }
    page++
}

HasMore ist ein boolescher Wert, den Short.io explizit zurückgibt – kein Parsen von Cursorn, kein Verfolgen der letzten ID. Ihre API ist eine der am besten konzipierten unter den fünf Anbietern, die wir unterstützen.

Short.io hat ein „Private“-Flag pro Link. Wir importieren private Links als Elido-Links mit is_active=false, sodass der Slug am Edge nicht aufgelöst wird. Der Benutzer schaltet sie nach einer stichprobenartigen Überprüfung des Imports selektiv über das Dashboard frei.

Die Begründung: Wenn ein Short.io-Link an der Quelle privat war, war es die Absicht des Benutzers, dass er nicht öffentlich aufgelöst wird. Würde man ihn als is_active=true importieren, würden URLs auftauchen, die absichtlich gesperrt waren. Der Import als is_active=false hält den Slug reserviert, aber unerreichbar, bis der Benutzer sich entscheidet – strikt sicherer als die Alternative.

isActive := !link.Private
linkID, err := w.links.InsertImported(ctx, sqldb.InsertImportedLinkParams{
    WorkspaceID:    job.WorkspaceID,
    DomainID:       job.TargetDomainID,
    Slug:           slug,
    DestinationURL: link.OriginalURL,
    Title:          truncate(link.Title, 250),
    Tags:           append(link.Tags, "imported:shortio"),
    IsActive:       isActive,
    CreatedByUserID: createdByUserID,
})

Dies ist ein kleiner oberflächlicher Unterschied zu Bitly (kein äquivalentes Flag) und Rebrandly (kein äquivalentes Flag). Es lohnt sich, dies im Post-Import-Rezept hervorzuheben, damit der Benutzer versteht, warum einige importierte Links nicht sofort aufgelöst werden.

Was wir nicht migrieren#

Die A/B-Split-Test-Konfigurationen von Short.io haben keinen sauberen Export – sie sind ein In-App-Builder, der keine deterministische JSON-Struktur über die REST API ausgibt. Bauen Sie diese nach dem Import als Elido smart-link rules neu auf; die Syntax ist ausdrucksstärker, aber das mentale Modell ist dasselbe.

Die Historie pro Klick ist das universelle Limit bei jeder Migrationsquelle. Die Daten pro Klick von Short.io liegen in deren Analytics-Export, der nur für den Team-Plan verfügbar ist (abgerufen am 2026-05-22) und als aggregierte Zähler statt als Ereignisse pro Klick ausgegeben wird. Neue Klicks landen ab dem Cutover in der Elido-Analytics.

QR-Designs und die UTM-Presets pro Link – dieselbe Geschichte wie bei Bitly und Rebrandly. Mit imported:shortio getaggt, bereit für Bulk-Follow-ups über Elido campaigns.

Domain-Übergabe#

Der interessante Short.io-Anwendungsfall ist: „Ich betreibe eine Brand-Domain auf Short.io und möchte sie zu Elido umziehen, ohne die URL zu ändern“. Die Migration wickelt die Link-Seite sauber ab; die DNS-Seite ist eine CNAME-Änderung.

Wir dokumentieren die Übergabesequenz auf der /migrate-from/shortio Landingpage – halten Sie beide Oberflächen parallel aktiv, bis Ihr Short.io-Abonnement endet, und zeigen Sie dann mit dem DNS auf Elido. Es gibt keine Eile, Short.io an dem Tag abzuschalten, an dem der Import endet.

Custom domains in Elido verwenden Caddys On-Demand TLS mit domain-manager als Allow-list-Quelle, sodass der Cutover eine CNAME-Änderung plus ein API-Aufruf zur Domain-Verifizierung ist. Kein Zertifikats-Tanz auf der Seite des Benutzers.

Konfliktlösung und der Worker-Vertrag#

Identisch mit Bitly und Rebrandly – Suffix-Walks mylink-2, mylink-3, … bei Kollision; Skip lässt den bestehenden Elido-Link in Ruhe und protokolliert die Quellzeile; Fail bricht beim ersten Konflikt ab. Das Nachschlagen erfolgt durch einen indizierten Lesezugriff pro Zeile.

Der Worker-Vertrag — MaxLinksPerImport=50_000, ImportRunBudget=30*time.Minute, progressEvery=50, errorLogCap=1_000 — wird von allen fünf Anbietern geteilt. Diese Konstanten erledigen den Großteil der Arbeit und sind keine Konfigurations-Knöpfe. Sie sind der Vertrag, den die UI des Dashboard-Pollings voraussetzt.

Token-Handhabung#

bgCtx := context.WithoutCancel(r.Context())
go h.shortio.Run(bgCtx, job.ID, imports.ShortioJobOptions{
    Token:    req.Token,
    DomainID: req.DomainID,
})

source_token_id bleibt NULL. Dieselbe One-Shot-Semantik wie bei Bitly und Rebrandly – der Benutzer fügt den Token einmal ein, der Worker läuft, der Token wird nach Abschluss aus dem Arbeitsspeicher entfernt. Wir persistieren ihn nicht, da der Wert der Persistenz (wiederkehrende Nutzung) nicht auf Migrationen zutrifft.

context.WithoutCancel hält den Worker über den HTTP-Request hinaus am Leben, der ihn ausgelöst hat. Dasselbe Muster wie bei jedem anderen Migrationsanbieter in diesem Rollout.

Vergleich mit dem CSV-Export-Pfad#

Short.io bietet einen CSV-Export bei Team-Plänen. Wir haben REST gegenüber CSV gewählt, weil:

  • REST Short.io-Tags strukturell beibehält. CSV flacht sie zu einer kommagetrennten Zeichenkette ab, die ein Aufteilen nach dem Parsen erfordert.
  • REST das private-Flag offenlegt. CSV enthält es nicht konsistent.
  • REST uns einen deterministischen Fortschritt gibt (gesehene Links / verbleibende Links). CSV ist ein einmaliger Datei-Upload ohne Fortschrittssignal während des Vorgangs.
  • REST plan-agnostisch ist – jeder Short.io-Plan bietet Zugriff auf /links. Der CSV-Export ist nur für Teams verfügbar.

Der CSV-Pfad bleibt für Benutzer mit alten Short.io-Konten in der Hinterhand, deren API-Token widerrufen wurde, die aber noch eine CSV aus dem letzten Export haben.

Wiederaufnehmbarkeit und das Deployment-Problem#

Dasselbe Abwägung wie bei den ersten beiden Migrationen. Der Worker läuft im Prozess; ein Deployment während des Imports beendet die Goroutine. Das Feld import_jobs.last_progress_at plus der 5-Minuten-Cronjob zum Bereinigen hängender Prozesse setzt jede running-Zeile ohne Fortschritt in den letzten 30 Minuten auf failed. Ein erneuter Durchlauf ist dank Suffix und Skip idempotent.

Für Konten mit mehr als 10.000 Links über mehrere Short.io-Domains hinweg hilft hier das Job-Design pro Domain – jede Domain ist unabhängig durch das 30-Minuten-Budget begrenzt, sodass ein Deployment während der dritten Domain nicht die Arbeit der ersten beiden verliert.

Wie es weitergeht#

Zwei weitere Anbieter folgen noch:

  • Dub.coGET /api/links?projectSlug=…&limit=100. Ordner werden zu Tags abgeflacht. Die sauberste API der fünf.
  • TinyURL — Pro/Bulk REST API mit 100 pro Seite. Die kostenlose Version von TinyURL hat keine API und wird nie eine haben; das bleibt ein manueller Pfad.

Nach Dub und TinyURL ist der Tier-3-Rollout abgeschlossen. Die fünf Migrations-Landingpages (/migrate-from/bitly, /migrate-from/rebrandly, /migrate-from/shortio, /migrate-from/dub, /migrate-from/tinyurl) und die fünf technischen Blogbeiträge decken jede Anbieter-Wechsel-Anfrage ab, die ein Nutzer auf der Suche nach einer Bitly-Alternative stellen könnte.

Falls Sie mit einem Short.io-Vergleich gezögert haben, weil die Migrationsgeschichte nicht dokumentiert war: Sie ist jetzt dokumentiert. Probieren Sie es aus — vom API-Key + Domain bis zum letzten importierten Link in unter sechs Minuten für typische Konten.

Verwandtes im Blog#

Elido testen

URL-Shortener mit EU-Hosting: eigene Domains, tiefe Analytik und eine offene API. Kostenloser Tarif — keine Kreditkarte nötig.

Tags
short.io migration
url shortener
go worker
data migration
engineering
tier 3 integrations

Weiterlesen