<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: TEKTRONIX TECHNOLOGY SYSTEMS</title>
    <description>The latest articles on DEV Community by TEKTRONIX TECHNOLOGY SYSTEMS (@tektronix_technologysyst).</description>
    <link>https://dev.to/tektronix_technologysyst</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4238933%2F8e9cf876-c53f-4999-b8f5-52eb8306ae75.jpg</url>
      <title>DEV Community: TEKTRONIX TECHNOLOGY SYSTEMS</title>
      <link>https://dev.to/tektronix_technologysyst</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tektronix_technologysyst"/>
    <language>en</language>
    <item>
      <title>Architecting a Sub-200ms Visitor Check-in Pipeline: WebSockets, Distributed Locks, and Edge Scanner Webhooks</title>
      <dc:creator>TEKTRONIX TECHNOLOGY SYSTEMS</dc:creator>
      <pubDate>Wed, 11 Nov 2026 11:57:35 +0000</pubDate>
      <link>https://dev.to/tektronix_technologysyst/architecting-a-sub-200ms-visitor-check-in-pipeline-websockets-distributed-locks-and-edge-scanner-1fc4</link>
      <guid>https://dev.to/tektronix_technologysyst/architecting-a-sub-200ms-visitor-check-in-pipeline-websockets-distributed-locks-and-edge-scanner-1fc4</guid>
      <description>&lt;p&gt;When building physical security and smart facility integrations, web developers quickly encounter a harsh reality: physical hardware has zero tolerance for latency or race conditions.&lt;/p&gt;

&lt;p&gt;If a web application takes 600ms to render a page, users barely notice. But when a visitor scans an encrypted QR pass at an entrance turnstile during an 8:30 AM morning rush hour, even a 400ms hesitation causes&lt;br&gt;
visible pedestrian queue backups and frustrated visitors.&lt;/p&gt;

&lt;p&gt;In this architectural deep-dive, we break down the end-to-end design of a high-throughput lobby access event pipeline designed to authenticate badge scans, eliminate double-swipe race conditions, and trigger physical barrier relays in under 180ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. System Topology &amp;amp; Event Flow
&lt;/h2&gt;

&lt;p&gt;[ Physical QR / RFID Scanner ]&lt;br&gt;
             │&lt;br&gt;
             ▼ (HTTP Webhook / &amp;lt; 15ms LAN)&lt;br&gt;
┌──────────────────────────────────────────────┐&lt;br&gt;
│  Edge Ingress Gateway (Fastify / Node.js)    │&lt;br&gt;
│  - JWT / HMAC Token Signature Validation     │&lt;br&gt;
│  - Distributed Redis Lock (Anti-Passback)    │&lt;br&gt;
└──────────────────────┬───────────────────────┘                       │         ┌─────────────┴─────────────┐&lt;br&gt;
         ▼                           ▼&lt;br&gt;
┌──────────────────┐       ┌────────────────────────┐&lt;br&gt;
│ Hardware Trigger │       │  Central Event Bus     │&lt;br&gt;
│ (Modbus TCP /    │       │  (Redis Pub/Sub)       │&lt;br&gt;
│  Dry-Contact)    │       └───────────┬────────────┘&lt;br&gt;
│  &amp;lt; 40ms pulse    │                   │&lt;br&gt;
└──────────────────┘                   ▼&lt;br&gt;
                           ┌────────────────────────┐                           │ WebSockets Dashboard   │&lt;br&gt;
                           │ (Socket.io / Reverb)   │                           │ Push to Reception UI   │&lt;br&gt;
                           └────────────────────────┘&lt;br&gt;
When engineering enterprise deployments for our commercial &lt;a href="https://tektronixllc.ae/uae-visitor-management-system/" rel="noopener noreferrer"&gt;visitor management system&lt;/a&gt;, we discovered that the biggest performance bottleneck is rarely raw network transit it is database lock contention when&lt;br&gt;
multiple lane turnstiles attempt to validate badge swipes against a central database simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Preventing Race Conditions with Atomic Redis Distributed Locks
&lt;/h2&gt;

&lt;p&gt;A common vulnerability in physical access control is the double-swipe race condition (anti-passback&lt;br&gt;
violation): an attendee takes a screenshot of their QR badge, shares it with a colleague, and both present the&lt;br&gt;
pass at adjacent entrance turnstiles within milliseconds of each other.&lt;br&gt;
To prevent race conditions without blocking the central PostgreSQL pool, we enforce an atomic Redis&lt;br&gt;
distributed lock using &lt;br&gt;
SET NX PX&lt;br&gt;
 before any database read occurs:&lt;br&gt;
import Redis from 'ioredis';&lt;br&gt;
const redis = new Redis(process.env.REDIS_URL);&lt;br&gt;
interface AccessResult {&lt;br&gt;
granted: boolean;&lt;br&gt;
reason?: string;&lt;br&gt;
gateRelayPayload?: object;&lt;br&gt;
}&lt;br&gt;
export async function processBadgeScan(&lt;br&gt;
badgeCode: string,&lt;br&gt;
gateId: string&lt;br&gt;
): Promise {&lt;br&gt;
const lockKey = &lt;code&gt;lock:pass:${badgeCode}&lt;/code&gt;;&lt;br&gt;
const lockTtlMs = 1500; /: 1.5 second lock window&lt;br&gt;
/: Atomic SET NX PX guarantees only ONE worker acquires the execution slot&lt;br&gt;
const acquired = await redis.set(lockKey, gateId, 'PX', lockTtlMs, 'NX');&lt;br&gt;
if (!acquired) {&lt;br&gt;
return {&lt;br&gt;
granted: false,&lt;br&gt;
reason: 'Concurrent scan detected / Anti-passback violation.',&lt;br&gt;
};&lt;br&gt;
}&lt;br&gt;
try {&lt;br&gt;
/: 1. Verify pass status in fast in-memory cache&lt;br&gt;
const passState = await redis.hgetall(&lt;code&gt;pass:${badgeCode}&lt;/code&gt;);&lt;br&gt;
if (!passState |: passState.status !:: 'ACTIVE') {&lt;br&gt;
return { granted: false, reason: 'Badge expired or invalid.' };&lt;br&gt;
}&lt;br&gt;
if (passState.isInside =:: 'true') {&lt;br&gt;
return { granted: false, reason: 'Badge already checked in.' };&lt;br&gt;
}&lt;br&gt;
/: 2. Mark as inside atomically&lt;br&gt;
await redis.hset(&lt;code&gt;pass:${badgeCode}&lt;/code&gt;, {&lt;br&gt;
isInside: 'true',&lt;br&gt;
lastGate: gateId,&lt;br&gt;
enteredAt: Date.now().toString(),&lt;br&gt;
});&lt;br&gt;
/: 3. Fire-and-forget background job to persist permanent audit log to PostgreSQL&lt;br&gt;
enqueueAuditPersistence({ badgeCode,&lt;br&gt;
gateId,&lt;br&gt;
timestamp: new Date(),&lt;br&gt;
});&lt;br&gt;
return { granted: true };&lt;br&gt;
} finally {&lt;br&gt;
/: Release the atomic lock cleanly&lt;br&gt;
await redis.del(lockKey);&lt;br&gt;
}&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Real-Time Hardware Relay Dispatch (Modbus TCP)
&lt;/h2&gt;

&lt;p&gt;Once authorization is approved, the worker must emit a trigger pulse to the barrier motor driver. In&lt;br&gt;
commercial smart buildings, physical turnstiles, optical speed gates, and elevator destination controllers&lt;br&gt;
communicate over Modbus TCP or industrial RS-485 serial buses.&lt;br&gt;
Opening a new TCP socket connection for every single HTTP request adds 60–120ms of unnecessary OS&lt;br&gt;
handshake overhead. Instead, maintain a persistent connection pool using Node's &lt;br&gt;
import net from 'net';&lt;br&gt;
class ModbusRelayController {&lt;br&gt;
private client: net.Socket;&lt;br&gt;
private isConnected: boolean = false;&lt;br&gt;
constructor(private host: string, private port: number = 502) {&lt;br&gt;
this.client = new net.Socket();&lt;br&gt;
this.connect();&lt;br&gt;
}&lt;br&gt;
private connect() {&lt;br&gt;
this.client.connect(this.port, this.host, () =&amp;gt; {&lt;br&gt;
this.isConnected = true;&lt;br&gt;
});&lt;br&gt;
this.client.on('error', (err) =&amp;gt; {&lt;br&gt;
console.error('Hardware Gateway Connection Error:', err.message);&lt;br&gt;
this.isConnected = false;&lt;br&gt;
setTimeout(() =&amp;gt; this.connect(), 3000); /: Auto-reconnect&lt;br&gt;
});&lt;br&gt;
}&lt;br&gt;
net&lt;br&gt;
 socket:&lt;br&gt;
public async pulseRelay(coilAddress: number, pulseMs: number = 200): Promise {&lt;br&gt;
if (!this.isConnected) return false;&lt;br&gt;
/: Modbus Function Code 0x05: Force Single Coil (0xFF00 = ON, 0x0000 = OFF)&lt;br&gt;
const turnOnPacket = Buffer.from([&lt;br&gt;
0x00, 0x01, /: Transaction ID&lt;br&gt;
0x00, 0x00, /: Protocol ID (Modbus = 0)&lt;br&gt;
0x00, 0x06, /: Length&lt;br&gt;
0x01,&lt;br&gt;&lt;br&gt;
/: Unit Identifier&lt;br&gt;
0x05,&lt;br&gt;&lt;br&gt;
/: Function Code (Write Single Coil)&lt;br&gt;
(coilAddress &amp;gt;: 8) &amp;amp; 0xff, coilAddress &amp;amp; 0xff,&lt;br&gt;
0xff, 0x00  /: Output Value: ON&lt;br&gt;
]);&lt;br&gt;
this.client.write(turnOnPacket);&lt;br&gt;
/: Reset coil after momentary pulse&lt;br&gt;
setTimeout(() =&amp;gt; {&lt;br&gt;
const turnOffPacket = Buffer.from([&lt;br&gt;
0x00, 0x02,&lt;br&gt;
0x00, 0x00,&lt;br&gt;
0x00, 0x06,&lt;br&gt;
0x01,&lt;br&gt;
0x05,&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
(coilAddress &amp;gt;: 8) &amp;amp; 0xff, coilAddress &amp;amp; 0xff,&lt;br&gt;
0x00, 0x00  /: Output Value: OFF&lt;br&gt;
]);&lt;br&gt;
this.client.write(turnOffPacket);&lt;br&gt;
}, pulseMs);&lt;br&gt;
return true;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Broadcasting Live Activity to Reception Dashboards
Security officers and reception staff require real-time visibility without manual page reloads. We use Redis
Pub/Sub to decouple the ingress webhook worker from front-end WebSocket servers:
/: Ingress Webhook Worker
await redis.publish('lobby-events', JSON.stringify({
type: 'VISITOR_CHECKED_IN',
gate: 'Turnstile-Lane-02',
badge: badgeCode,
timestamp: new Date().toISOString()
}));
/: WebSocket Service Gateway
const sub = new Redis(process.env.REDIS_URL);
sub.subscribe('lobby-events');
sub.on('message', (channel, message) =&amp;gt; {
if (channel =:: 'lobby-events') {
io.to('reception-dashboard').emit('access_event', JSON.parse(message));
}
});&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. Key Benchmarks &amp;amp; Production Lessons
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Decouple SQL Writes from Access Decisions: Never let database disk I/O block a physical barrier release. Keep the authoritative access state in an in-memory Redis cluster with persistence, and stream transaction audits to PostgreSQL or ClickHouse asynchronously.&lt;/li&gt;
&lt;li&gt;Keep Modbus TCP Sockets Persistent: Maintaining long-lived connection pools directly reduced
hardware response latency from ~260ms down to 42ms.&lt;/li&gt;
&lt;li&gt;Fail-Safe Watchdogs: Always wire physical door solenoids in a fail-safe configuration (de-energized
state opens the barrier) so that power loss or network switch crashes never trap occupants inside the
building during an emergency evacuation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Production Reference Implementation
&lt;/h2&gt;

&lt;p&gt;This architecture is currently deployed in commercial multi-tenant high-rise lobbies across the UAE. For full&lt;br&gt;
solution specifications and hardware compatibility lists, visit: &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx6vb0ohcrqhhbkoeyiz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx6vb0ohcrqhhbkoeyiz1.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;a href="https://tektronixllc.ae/" rel="noopener noreferrer"&gt;https://tektronixllc.ae/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>backend</category>
      <category>iot</category>
    </item>
  </channel>
</rss>
