Skip to Content
GuidesProduction Deployment

πŸš€ Production Deployment Guide

Complete guide for deploying GoCharting SDK in production environments with best practices, performance optimization, and monitoring.

πŸ“‹ Pre-Deployment Checklist

  • Valid production license key obtained
  • License domain matches production domain
  • Terms of service reviewed and accepted
  • Compliance requirements verified

βœ… Technical Requirements

  • Node.js 16+ installed (for build process)
  • Modern browser support verified
  • CDN/hosting infrastructure ready
  • SSL certificate configured
  • Monitoring tools set up

βœ… Performance Testing

  • Load testing completed
  • Memory usage profiled
  • Network latency measured
  • Error handling tested
  • Fallback mechanisms verified

πŸ—οΈ Deployment Architecture

Infrastructure Components

  1. CDN: Serve static SDK files
  2. Load Balancer: Distribute traffic
  3. Web Servers: Host your application
  4. Data APIs: Provide market data
  5. WebSocket Servers: Real-time data feeds
  6. Monitoring: Track performance and errors

πŸ”§ Build Configuration

Production Build Setup

// webpack.config.prod.js const path = require("path"); module.exports = { mode: "production", entry: "./src/index.js", output: { path: path.resolve(__dirname, "dist"), filename: "[name].[contenthash].js", publicPath: "/static/", }, optimization: { splitChunks: { chunks: "all", cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all", }, gocharting: { test: /[\\/]node_modules[\\/]gocharting-sdk[\\/]/, name: "gocharting", chunks: "all", }, }, }, }, externals: { // Use CDN versions for better caching react: "React", "react-dom": "ReactDOM", }, };

Environment Configuration

// config/production.js module.exports = { gocharting: { licenseKey: process.env.GOCHARTING_LICENSE_KEY, apiBaseUrl: process.env.API_BASE_URL, websocketUrl: process.env.WEBSOCKET_URL, // Performance settings performance: { maxCandles: 10000, updateFrequency: 100, animations: false, // Disable for better performance preloadData: true, }, // Error handling errorReporting: { enabled: true, endpoint: process.env.ERROR_REPORTING_URL, }, // Monitoring monitoring: { enabled: true, endpoint: process.env.MONITORING_URL, sampleRate: 0.1, // 10% sampling }, }, };

🌐 CDN and Caching Strategy

CDN Configuration

# nginx.conf server { listen 443 ssl http2; server_name your-domain.com; # SSL configuration ssl_certificate /path/to/certificate.crt; ssl_certificate_key /path/to/private.key; # Gzip compression gzip on; gzip_types text/css application/javascript application/json; # Static assets with long cache location /static/ { expires 1y; add_header Cache-Control "public, immutable"; add_header X-Content-Type-Options nosniff; } # GoCharting SDK files location /sdk/ { expires 30d; add_header Cache-Control "public"; add_header Access-Control-Allow-Origin "*"; } # API endpoints location /api/ { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # CORS headers add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; } }

Cache Headers

// Express.js cache configuration app.use( "/sdk", express.static("node_modules/gocharting-sdk/dist", { maxAge: "30d", etag: true, lastModified: true, setHeaders: (res, path) => { if (path.endsWith(".js")) { res.setHeader("Cache-Control", "public, max-age=2592000"); // 30 days } if (path.endsWith(".css")) { res.setHeader("Cache-Control", "public, max-age=2592000"); // 30 days } }, }) );

⚑ Performance Optimization

Bundle Optimization

// Lazy load SDK for better initial page load const loadChart = async () => { const { createChart, DataProvider } = await import("gocharting-sdk"); return { createChart, DataProvider }; }; // Use dynamic imports const initChart = async () => { const { createChart } = await loadChart(); const chart = createChart("#chart", { symbol: "AAPL", interval: "1D", datafeed: myDatafeed, licenseKey: "YOUR_LICENSE_KEY", // ... other configuration }); return chart; };

Memory Management

class ChartManager { constructor() { this.charts = new Map(); this.cleanupInterval = setInterval(() => { this.cleanup(); }, 300000); // Cleanup every 5 minutes } createChart(id, config) { // Destroy existing chart if any if (this.charts.has(id)) { this.destroyChart(id); } const chart = new ProfessionalChart(config); this.charts.set(id, { instance: chart, lastUsed: Date.now(), }); return chart; } destroyChart(id) { const chartData = this.charts.get(id); if (chartData) { chartData.instance.destroy(); this.charts.delete(id); } } cleanup() { const now = Date.now(); const maxAge = 30 * 60 * 1000; // 30 minutes for (const [id, chartData] of this.charts) { if (now - chartData.lastUsed > maxAge) { this.destroyChart(id); } } } destroy() { clearInterval(this.cleanupInterval); for (const id of this.charts.keys()) { this.destroyChart(id); } } }

Data Optimization

class OptimizedDataProvider extends DataProvider { constructor() { super(); this.cache = new Map(); this.maxCacheSize = 100; } async getBars(symbolInfo, resolution, periodParams) { const cacheKey = `${symbolInfo.name}-${resolution}-${periodParams.from}-${periodParams.to}`; // Check cache first if (this.cache.has(cacheKey)) { return this.cache.get(cacheKey); } // Fetch data const data = await this.fetchBarsFromAPI( symbolInfo, resolution, periodParams ); // Cache with size limit if (this.cache.size >= this.maxCacheSize) { const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); } this.cache.set(cacheKey, data); return data; } // Implement data compression for large datasets compressData(bars) { return bars.map((bar) => ({ t: bar.time, o: Math.round(bar.open * 100) / 100, h: Math.round(bar.high * 100) / 100, l: Math.round(bar.low * 100) / 100, c: Math.round(bar.close * 100) / 100, v: bar.volume, })); } }

πŸ“Š Monitoring and Analytics

Error Tracking

// Error tracking setup class ErrorTracker { constructor(config) { this.config = config; this.setupGlobalErrorHandling(); } setupGlobalErrorHandling() { window.addEventListener("error", (event) => { this.reportError({ type: "javascript", message: event.message, filename: event.filename, lineno: event.lineno, colno: event.colno, stack: event.error?.stack, }); }); window.addEventListener("unhandledrejection", (event) => { this.reportError({ type: "promise", message: event.reason?.message || "Unhandled promise rejection", stack: event.reason?.stack, }); }); } reportError(error) { if (!this.config.enabled) return; fetch(this.config.endpoint, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ ...error, timestamp: new Date().toISOString(), userAgent: navigator.userAgent, url: window.location.href, }), }).catch(console.error); } } // Initialize error tracking const errorTracker = new ErrorTracker({ enabled: true, endpoint: "/api/errors", });

Performance Monitoring

// Performance monitoring class PerformanceMonitor { constructor() { this.metrics = {}; this.startTime = performance.now(); } mark(name) { this.metrics[name] = performance.now() - this.startTime; } measure(name, startMark, endMark) { const start = this.metrics[startMark] || 0; const end = this.metrics[endMark] || performance.now() - this.startTime; this.metrics[name] = end - start; } report() { // Send metrics to monitoring service fetch("/api/metrics", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ metrics: this.metrics, timestamp: new Date().toISOString(), }), }); } } // Usage const monitor = new PerformanceMonitor(); monitor.mark("chart-init-start"); const chart = new ProfessionalChart(config); chart.onChartReady(() => { monitor.mark("chart-init-end"); monitor.measure( "chart-initialization", "chart-init-start", "chart-init-end" ); monitor.report(); });

πŸ”’ Security Best Practices

Content Security Policy

<!-- CSP headers --> <meta http-equiv="Content-Security-Policy" content=" default-src 'self'; script-src 'self' 'unsafe-inline' https://gocharting.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.yourbroker.com wss://ws.yourbroker.com; img-src 'self' data: https:; " />

API Security

// Secure API configuration class SecureDataProvider extends DataProvider { constructor(config) { super(); this.apiKey = config.apiKey; this.baseUrl = config.baseUrl; this.rateLimiter = new RateLimiter(100, 60000); // 100 requests per minute } async makeRequest(endpoint, options = {}) { // Rate limiting await this.rateLimiter.acquire(); // Add authentication const headers = { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", ...options.headers, }; // Request timeout const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); try { const response = await fetch(`${this.baseUrl}${endpoint}`, { ...options, headers, signal: controller.signal, }); clearTimeout(timeoutId); if (!response.ok) { throw new Error( `HTTP ${response.status}: ${response.statusText}` ); } return await response.json(); } catch (error) { clearTimeout(timeoutId); throw error; } } }

πŸš€ Deployment Scripts

Automated Deployment

#!/bin/bash # deploy.sh set -e echo "Starting GoCharting SDK deployment..." # Build application echo "Building application..." npm run build # Run tests echo "Running tests..." npm test # Deploy to staging echo "Deploying to staging..." rsync -avz --delete dist/ staging-server:/var/www/app/ # Run smoke tests echo "Running smoke tests..." npm run test:smoke # Deploy to production echo "Deploying to production..." rsync -avz --delete dist/ production-server:/var/www/app/ # Verify deployment echo "Verifying deployment..." curl -f https://your-domain.com/health || exit 1 echo "Deployment completed successfully!"

Health Check Endpoint

// health.js app.get("/health", (req, res) => { const health = { status: "healthy", timestamp: new Date().toISOString(), version: process.env.APP_VERSION, checks: { database: "healthy", api: "healthy", gocharting: "healthy", }, }; // Check GoCharting SDK availability try { // Verify license key const licenseValid = validateLicense( process.env.GOCHARTING_LICENSE_KEY ); health.checks.gocharting = licenseValid ? "healthy" : "unhealthy"; } catch (error) { health.checks.gocharting = "unhealthy"; health.status = "unhealthy"; } const statusCode = health.status === "healthy" ? 200 : 503; res.status(statusCode).json(health); });

πŸ“ˆ Scaling Considerations

Horizontal Scaling

# docker-compose.yml version: "3.8" services: app: image: your-app:latest replicas: 3 environment: - GOCHARTING_LICENSE_KEY=${GOCHARTING_LICENSE_KEY} - API_BASE_URL=${API_BASE_URL} ports: - "3000-3002:3000" nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf depends_on: - app

Load Testing

// load-test.js const { check } = require("k6"); const http = require("k6/http"); export let options = { stages: [ { duration: "2m", target: 100 }, // Ramp up { duration: "5m", target: 100 }, // Stay at 100 users { duration: "2m", target: 200 }, // Ramp up to 200 users { duration: "5m", target: 200 }, // Stay at 200 users { duration: "2m", target: 0 }, // Ramp down ], }; export default function () { const response = http.get("https://your-domain.com/chart"); check(response, { "status is 200": (r) => r.status === 200, "response time < 2s": (r) => r.timings.duration < 2000, }); }

Follow these guidelines for a successful production deployment of GoCharting SDK!

Last updated on