Lit Element Disaster Recovery Plan —
Lit Element DR
Lit Element Web Components Disaster Recovery CDN Failover Service Worker Offline State Recovery Error Boundary Rollback Health Check Resilience Progressive Enhancement
| DR Strategy | RTO | RPO | Complexity | เหมาะกับ |
|---|---|---|---|---|
| CDN Failover | 30 วินาที | 0 | ปานกลาง | Static Assets |
| Service Worker | 0 (Cached) | Last cache | สูง | Offline Apps |
| State Recovery | ทันที | Last save | ต่ำ | Form Data |
| Rollback Deploy | 2-5 นาที | Previous ver | ต่ำ | Bad Deploys |
Lit Element Components
=== Lit Element with Error Boundary ===
npm install lit
error-boundary.ts
import { LitElement, html, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
@customElement('error-boundary')
export class ErrorBoundary extends LitElement {
@state() hasError = false;
@state() errorMessage = '';
static styles = css`
.error-container {
padding: 20px;
border: 2px solid #e74c3c;
border-radius: 8px;
background: #fdf2f2;
text-align: center;
}
.retry-btn {
margin-top: 12px;
padding: 8px 16px;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
`;
connectedCallback() {
super.connectedCallback();
window.addEventListener('error', this._handleError.bind(this));
window.addEventListener('unhandledrejection', this._handleRejection.bind(this));
}
_handleError(event) {
this.hasError = true;
this.errorMessage = event.message;
this._reportError(event);
}
_handleRejection(event) {
this.hasError = true;
this.errorMessage = event.reason?.message || 'Async error';
}
_reportError(error) {
fetch('/api/errors', {
method: 'POST',
body: JSON.stringify({ error: error.message, stack: error.stack })
}).catch(() => {});
}
_retry() {
this.hasError = false;
this.errorMessage = '';
}
render() {
if (this.hasError) {
return html`
<div class="error-container">
<h3>Something went wrong</h3>
# <button class="retry-btn" @click=>Retry</button>
</div>`;
}
return html`<slot></slot>`;
}
}
from dataclasses import dataclass
@dataclass
class Component:
name: str
type: str
size_kb: float
lazy: bool
cached: bool
status: str
components = [
Component("app-shell", "Layout", 8.5, False, True, "Active"),
Component("error-boundary", "Utility", 2.1, False, True, "Active"),
Component("offline-banner", "UI", 1.5, False, True, "Active"),
Component("data-table", "Feature", 15.2, True, True, "Active"),
Component("chart-widget", "Feature", 25.0, True, True, "Active"),
Component("form-wizard", "Feature", 12.0, True, True, "Active"),
Component("notification-toast", "UI", 3.0, False, True, "Active"),
]
print("=== Lit Components ===")
total_size = sum(c.size_kb for c in components)
for c in components:
lazy = "Lazy" if c.lazy else "Eager"
cached = "Cached" if c.cached else "No Cache"
print(f" [{c.status}] {c.name} ({c.type})")
print(f" Size: {c.size_kb}KB | Load: {lazy} | {cached}")
print(f"\n Total Bundle: {total_size:.1f}KB")
Service Worker
=== Service Worker for DR ===
sw.js — Cache-first with Network Fallback
const CACHE_NAME = 'app-v2.1.0';
const OFFLINE_URL = '/offline.html';
const PRECACHE_URLS = [
'/',
'/index.html',
'/offline.html',
'/assets/app-shell.js',
'/assets/error-boundary.js',
'/assets/styles.css',
'/assets/logo.svg',
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(PRECACHE_URLS);
})
);
self.skipWaiting();
});
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => {
return caches.match(OFFLINE_URL);
})
);
return;
}
event.respondWith(
caches.match(event.request).then((cached) => {
if (cached) return cached;
return fetch(event.request).then((response) => {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, clone);
});
return response;
}).catch(() => {
return new Response('Offline', { status: 503 });
});
})
);
});
@dataclass
class CacheStrategy:
pattern: str
strategy: str
ttl: str
fallback: str
strategies = [
CacheStrategy("HTML Pages", "Network-first", "5 min", "Offline page"),
CacheStrategy("JS Bundles", "Cache-first", "30 days", "Cached version"),
CacheStrategy("CSS Styles", "Cache-first", "30 days", "Cached version"),
CacheStrategy("Images", "Cache-first", "7 days", "Placeholder"),
CacheStrategy("API Data", "Network-first", "1 min", "Stale cache"),
CacheStrategy("Fonts", "Cache-first", "90 days", "System font"),
]
print("\n=== Cache Strategies ===")
for s in strategies:
print(f" [{s.strategy}] {s.pattern}")
print(f" TTL: {s.ttl} | Fallback: {s.fallback}")
DR Plan
# === Disaster Recovery Plan ===
@dataclass
class DRScenario:
scenario: str
impact: str
detection: str
recovery: str
rto: str
scenarios = [
DRScenario("CDN Down", "Assets ไม่โหลด", "Health check fail", "Switch to backup CDN", "30s"),
DRScenario("API Down", "Data ไม่โหลด", "API health check", "Show cached data + retry", "0s"),
DRScenario("Bad Deploy", "App broken", "Error rate spike", "Rollback to previous version", "2min"),
DRScenario("DNS Failure", "Site unreachable", "External monitor", "Switch DNS provider", "5min"),
DRScenario("DB Corruption", "Data loss", "Data integrity check", "Restore from backup", "30min"),
DRScenario("DDoS Attack", "Site slow/down", "Traffic spike alert", "Enable WAF + rate limit", "5min"),
]
print("DR Scenarios:")
for s in scenarios:
print(f" [{s.rto}] {s.scenario}")
print(f" Impact: {s.impact}")
print(f" Detection: {s.detection}")
print(f" Recovery: {s.recovery}")
# DR Checklist
checklist = [
"Service Worker: Precache critical assets",
"CDN Failover: Backup CDN configured and tested",
"State Backup: Auto-save to LocalStorage every 30s",
"Error Boundary: Wrap all route components",
"Offline Page: Custom offline.html with retry",
"Health Check: Monitor CDN API DNS every 30s",
"Rollback: One-click rollback to previous deploy",
"Runbook: Document every DR scenario and steps",
]
print(f"\n\nDR Checklist:")
for i, c in enumerate(checklist, 1):
print(f" {i}. {c}")
เคล็ดลับ
- SW: Service Worker Precache Critical Assets ทุกครั้ง
- Error: Error Boundary ครอบทุก Component สำคัญ
- Cache: Cache-first สำหรับ Static, Network-first สำหรับ Data
- Rollback: ต้อง Rollback ได้ภายใน 2 นาทีเสมอ
- Test: ซ้อม DR ทุกเดือน ทดสอบทุก Scenario
Lit Element คืออะไร
Library Web Components เล็ก เร็ว TypeScript Reactive Properties Template Scoped Styles Reusable React Vue Angular Google YouTube