[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-10 22:08:15 +09:00
parent 21ac3ed255
commit 504fd5fb42
3011 changed files with 380280 additions and 206977 deletions
+313
View File
@@ -0,0 +1,313 @@
---
id: web-web-locks-api
title: Web Locks API — tab 간 mutex
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [web, lock, vibe-coding]
tech_stack: { language: "TS", applicable_to: ["Frontend"] }
applied_in: []
aliases: [Web Locks, navigator.locks, tab synchronization, broadcast channel, mutex, exclusive lock]
---
# Web Locks API
> 같은 origin 의 여러 tab 가 race condition. **`navigator.locks` 가 mutex**. Sync between tabs / workers. Modern browsers.
## 📖 핵심 개념
- 같은 origin 의 다른 tab / worker / iframe 사이.
- Exclusive (1) 또는 shared (read).
- 매 lock 가 자동 release (tab close).
- `BroadcastChannel` 와 함께 사용.
## 💻 코드 패턴
### Exclusive lock
```ts
await navigator.locks.request('my-resource', async (lock) => {
// 매 origin 에서 1 곳 만.
await criticalSection();
});
// → Lock 자동 release.
```
### Shared lock (read)
```ts
await navigator.locks.request('config', { mode: 'shared' }, async (lock) => {
// 여러 tab 가 동시 read.
});
await navigator.locks.request('config', { mode: 'exclusive' }, async (lock) => {
// Write — shared 가 wait.
});
```
→ Reader / writer.
### Use case: leader election
```ts
// 1 tab 만 가 background work
let isLeader = false;
navigator.locks.request('leader', { mode: 'exclusive' }, async () => {
isLeader = true;
while (isLeader) {
await pollServer();
await new Promise(r => setTimeout(r, 5000));
}
});
window.addEventListener('beforeunload', () => {
isLeader = false;
});
```
→ 새 tab 가 lock = leader.
→ "Service Worker 가 leader" 의 alternative.
### TryLock (안 wait)
```ts
const result = await navigator.locks.request('resource', { ifAvailable: true }, async (lock) => {
if (!lock) return 'busy';
// ...
return 'done';
});
```
`ifAvailable: true` = 잠겼으면 lock=null + callback 즉시.
### Timeout (own logic)
```ts
async function lockWithTimeout(name: string, ms: number, fn: () => Promise<void>) {
const ac = new AbortController();
setTimeout(() => ac.abort(), ms);
await navigator.locks.request(name, { signal: ac.signal }, fn);
}
```
→ N ms 안 lock 못 = AbortError.
### Query state
```ts
const { held, pending } = await navigator.locks.query();
console.log('Held locks:', held.map(l => l.name));
console.log('Pending:', pending.map(l => l.name));
```
→ Debug.
### vs SharedWorker
```
SharedWorker: 같은 origin tab 가 공유 worker.
Web Locks: 작은 mutex.
→ 둘 다 사용 가능.
SharedWorker = 큰 logic 공유.
Web Locks = small lock.
```
### vs BroadcastChannel
```
BroadcastChannel: tab 간 message.
Web Locks: tab 간 lock.
→ 함께 사용 흔함.
```
```ts
const channel = new BroadcastChannel('updates');
channel.postMessage({ type: 'config-changed' });
// Other tab
channel.onmessage = (e) => {
if (e.data.type === 'config-changed') {
reloadConfig();
}
};
```
### Use case: IndexedDB write coordinate
```ts
// 여러 tab 가 같은 data 변경 → conflict.
async function updateConfig(newValue) {
await navigator.locks.request('config-write', async () => {
const tx = db.transaction('config', 'readwrite');
await tx.objectStore('config').put(newValue);
});
}
```
### Service Worker + Web Locks
```ts
// Service worker
self.addEventListener('fetch', async (event) => {
await navigator.locks.request('cache-write', async () => {
const cache = await caches.open('v1');
cache.put(event.request, response);
});
});
```
→ Cache 가 tab 간 + worker 사이 안전.
### 함정
```
- Tab 간 만 (cross-origin X).
- Worker 도 같은 origin.
- Indexed DB transaction 가 별도 lock (혼동 X).
```
### Browser support
```
Chrome 69+, Edge 79+, FF 96+, Safari 15.4+.
→ 모든 modern.
```
### Polyfill 가 어려움
```
Cross-tab lock 가 native 만 신뢰.
Polyfill = localStorage 로 가능 (race condition 위험).
```
### Use case 모음
```
1. Leader election (single tab background work).
2. IndexedDB write serialize.
3. Cache 정리 (1 tab 만).
4. WebSocket 1 connection share.
5. Background sync coordinate.
```
### Single WebSocket pattern
```ts
async function connectIfLeader() {
await navigator.locks.request('ws-connection', async () => {
const ws = new WebSocket('wss://...');
// ws → BroadcastChannel 가 다른 tab 에 전달
ws.onmessage = (e) => {
bc.postMessage({ type: 'message', data: e.data });
};
// Hold lock — tab close = release
await new Promise(() => {});
});
}
```
→ 1 WS, N tab 공유.
### Lock 의 ordering
```
First-come, first-served (queue).
- Tab A request → wait.
- Tab B request → wait B.
- Tab C request → wait C.
- A 끝 → B 시작 → 등.
```
### Re-entrancy 안 됨
```ts
await navigator.locks.request('x', async () => {
// ❌ 재 lock — deadlock.
await navigator.locks.request('x', async () => {});
});
```
→ Promise pending forever.
### 일반 mutex 와 차이
```
일반 mutex: 같은 process.
Web Locks: cross-tab (다른 process).
→ Browser 가 origin-scoped lock manager.
```
### Auto-release
```
Tab close, navigation, crash:
→ Lock 자동 release.
⚠️ 매 lock 가 finite life — 무한 hang X.
```
### Production tip
```
- Lock 안 work 가 빠름 (다른 tab block).
- Long-running = SharedWorker 가 더 좋음.
- Critical path 만 lock.
- Debug 로 query() 활용.
```
### LiveBlocks / PartyKit (alternative)
```
Cross-tab sync = Web Locks 의 idea + cross-device.
→ Different problem (tab 가 아닌 user).
```
### 함정: Worker 안 사용
```ts
// Worker 안
self.onmessage = async (e) => {
await navigator.locks.request('x', async () => {
// OK — worker 도 same-origin lock 참여
});
};
```
### Same-site / origin / Tab 이해
```
example.com / about.html / 가 lock 공유.
example.com / sub.html / 도 공유.
sub.example.com 는 안 (다른 origin).
```
### Storage event (옛 방법)
```ts
// localStorage 변경 = 다른 tab 가 'storage' event.
// → Pseudo-lock (race condition 위험).
window.addEventListener('storage', (e) => {
if (e.key === 'lock-X' && e.newValue === 'taken') {
// ...
}
});
```
→ Web Locks 가 modern + 안전.
## 🤔 의사결정 기준
| 작업 | 추천 |
|---|---|
| Tab 간 mutex | Web Locks |
| 1 tab 만 background | Leader election |
| Tab 간 message | BroadcastChannel |
| Logic 공유 | SharedWorker |
| Try lock | `ifAvailable: true` |
| Timeout | AbortController + signal |
| Read/write | shared / exclusive mode |
## ❌ 안티패턴
- **localStorage 로 fake lock**: race.
- **Cross-origin lock 가정**: 안 됨.
- **Re-entrant lock**: deadlock.
- **Long work in lock**: 다른 tab freeze.
- **Auto-release 무시**: leak 가정.
- **Web Locks 만 + sync 없음**: BroadcastChannel 함께.
## 🤖 LLM 활용 힌트
- Web Locks 가 cross-tab mutex 의 답.
- Leader election + BroadcastChannel 가 SharedWorker 의 작은 alternative.
- Auto-release 가 큰 강점.
- Browser support 가 좋음 (modern).
## 🔗 관련 문서
- [[Web_Service_Worker_Patterns]]
- [[Web_PWA_Service_Worker]]
- [[CS_Distributed_Locks]]