Orchestration Patterns Proposal

Context, Observability & DX

Why "Arches"?

  1. 🏜️ Utah National Parks theme — follows our Zion monorepo naming

  2. 🌉 An arch bridges two things — orchestration services bridge frontend to backend

Opportunities for Improvement

Streamlining the Request Flow

async function fetchPerson(id: string, req: Request) {
  const session = req.session  // Where did this come from?
  const user = req.user        // Who attached this?
  
  axios.get(`/person/${id}`, {headers:{
    Authorization: `Bearer ${req.session.id}`
  }})
}

app.get('/person/:id', async (req, res) => {
  const person = await fetchPerson(req.params.id, req)
  res.json(person)
})

Enhancing Type Safety

interface Request {
  session?: any      // What shape is this?
  user?: any         // When is it populated?
  requestId?: string // Is this always set?
}

// Later in code...
if (req.user.permissions.includes('admin')) {
  // 💥 Runtime error: Cannot read property 'includes' of undefined
}

Proposed Improvement

AsyncLocalStorage

AsyncLocalStorage

// How it works under the hood
import { AsyncLocalStorage } from 'node:async_hooks'

const storage = new AsyncLocalStorage<RequestContext>()

// Middleware wraps each request
app.use((req, res, next) => {
  const context = { requestId: randomUUID(), startTime: Date.now() }
  storage.run(context, () => next())
})

// Anywhere in your code — no parameters needed
function getRequestId(): string {
  return storage.getStore()?.requestId
}
async function fetchPerson(id: string, req: Request) {
  const session = req.session  // Where did this come from?
  
  axios.get(`/person/${id}`, {headers:{
    Authorization: `Bearer ${req.session.id}`
  }})
}

app.get('/person/:id', async (req, res) => {
  const person = await fetchPerson(req.params.id, req)
  res.json(person)
})
async function fetchPerson(id: string) {
  axios.get(`/person/${id}`)
}





app.get('/person/:id', async (req, res) => {
  const person = await fetchPerson(req.params.id)
  res.json(person)
})

Before and After

// DO NOT attach request-scoped data to req
app.use((req, res, next) => {
  req.user = await getUser()           // ❌ Wrong
  req.featureFlags = parseFlags(req)   // ❌ Wrong
  req.t = i18n.t                       // ❌ Wrong
  next()
})

// DO THIS INSTEAD
import { getUser } from '@fs/arches-user'
import { getFeatureFlag } from '@fs/arches-flags'
import { getT } from '@fs/arches-locales'

async function processData() {
  const user = await getUser()  // ✅ Correct
  const {isOn} = await getFeatureFlag('new-feature')  // ✅ Correct
  const t = getT()  // ✅ Correct
  t('title')
}

Other Examples

Trade-offs (The "Magic" Question)

Arches

By Tyler Graf

Arches

  • 24