Skip to main content
5 Minute Quickstart

RUNTIME Serverless Functions

Deploy event-driven functions for stream orchestration. Multi-language support, stateful processing, sub-100ms latency.

⏱️ 5 min read
✓ Beginner friendly
🔧 JavaScript & Python
Docs/Quickstart/RUNTIME Setup

Prerequisites

  • 1.WAVE CLI installed: npm install -g wave-cli
  • 2.API key configured: wave auth:login
  • 3.Node.js 16+ or Python 3.8+ available

1Create Your First Function

JavaScript function for content moderation

// javascript/handler.js - Simple content moderation function
export async function handler(event) {
  const { streamId, viewers, duration } = event.data;

  console.log(`Stream ${streamId} detected ${viewers} viewers`);

  // Check if we should run moderation
  if (viewers > 100) {
    // Trigger content moderation on EDGE
    await event.context.edge.process({
      streamId,
      effects: ['content-detection'],
      webhook: 'https://yourapp.com/webhook/moderation'
    });
  }

  // Update PULSE analytics
  await event.context.analytics.record({
    event: 'stream_analyzed',
    streamId,
    viewerCount: viewers,
    duration,
    timestamp: new Date().toISOString()
  });

  return {
    success: true,
    message: `Processed stream with ${viewers} viewers`
  };
}

2Or Use Python

Python function for engagement campaigns

# python/handler.py - Viewer engagement campaign
import json
from datetime import datetime

async def handler(event):
    stream_id = event['data']['streamId']
    viewer_count = event['data']['viewers']

    # Check engagement threshold
    if viewer_count > 500:
        # Send notification to engaged viewers
        result = await event.context.vault.notify({
            'stream_id': stream_id,
            'message': 'Join our subscriber community for exclusive content!',
            'viewers_targeted': viewer_count,
            'action_url': 'https://yourapp.com/subscribe'
        })

        # Log the campaign
        await event.context.analytics.record({
            'event': 'engagement_campaign',
            'stream_id': stream_id,
            'viewers_notified': result['count'],
            'timestamp': datetime.now().isoformat()
        })

        return {'campaign_sent': True, 'viewers': result['count']}

    return {'campaign_sent': False}

3Deploy Your Function

Use the CLI to deploy

# Deploy function to RUNTIME
wave runtime:deploy handler.js --language javascript --trigger stream.viewer_joined

# Deploy Python function
wave runtime:deploy handler.py --language python --trigger stream.started

# List deployed functions
wave runtime:list

# View function logs
wave runtime:logs handler.js --tail

4Subscribe to Events

Your function receives events automatically

// Subscribe to stream events
wave.runtime.on('stream.started', async (event) => {
  console.log('Stream started:', event.streamId);
  // Automatically invokes your deployed function
});

// Subscribe to viewer events
wave.runtime.on('viewer.joined', async (event) => {
  console.log('Viewer joined:', event.viewerId, event.streamId);
  // Your function is automatically triggered
});

// Subscribe to custom events
wave.runtime.on('custom.moderation-required', async (event) => {
  const result = await wave.runtime.invoke('moderation-handler', {
    streamId: event.streamId,
    contentFlags: event.flags
  });
});

Advanced: Persistent State

Maintain state across invocations

Store data in PostgreSQL automatically

// Persist state across invocations
export async function handler(event) {
  const streamId = event.data.streamId;
  const ctx = event.context;

  // Get previous state
  const state = await ctx.state.get(`stream:${streamId}`);
  const viewCount = state?.viewCount || 0;

  // Update state
  const newState = {
    viewCount: viewCount + event.data.newViewers,
    lastUpdate: new Date().toISOString(),
    peakViewers: Math.max(state?.peakViewers || 0, viewCount + event.data.newViewers)
  };

  await ctx.state.set(`stream:${streamId}`, newState);

  // If peak reached, trigger milestone
  if (newState.peakViewers >= 1000) {
    await ctx.runtime.trigger('milestone-celebration', {
      streamId,
      milestone: newState.peakViewers
    });
  }

  return newState;
}

Error Handling & Retries

Robust error handling

// Robust error handling and retries
export async function handler(event) {
  const streamId = event.data.streamId;

  try {
    // Your business logic here
    const result = await processStream(streamId);
    return { success: true, result };
  } catch (error) {
    // Log error to Sentry
    event.context.logger.error('Stream processing failed', {
      streamId,
      error: error.message,
      stack: error.stack
    });

    // Record dead-letter event
    await event.context.analytics.record({
      event: 'function_error',
      streamId,
      error: error.message,
      timestamp: new Date().toISOString()
    });

    // Return graceful failure - function will auto-retry
    throw new Error(`Failed to process ${streamId}: ${error.message}`);
  }
}

Scheduled Execution

Run functions on a schedule

// Run function on a schedule (every hour)
wave runtime:schedule handler.js \
  --trigger "0 * * * *" \
  --language javascript

// Run daily reports
wave runtime:schedule daily-report.py \
  --trigger "0 0 * * *" \
  --language python \
  --context '{"type":"daily-summary"}'

Troubleshooting

Function not being triggered?

Check logs: wave runtime:logs --tail. Verify event subscription syntax.

Cold start too slow?

Use Go or Rust for faster cold starts. Keep warm with frequent invocations or scheduled execution.

State not persisting?

Ensure await ctx.state.set() completes before returning.

Next Steps

  • Explore all runtimes:

    JavaScript, Python, Go, and Rust are all supported

  • Integrate with EDGE:

    Combine RUNTIME orchestration with EDGE processing

  • Monitor with PULSE:

    Track function performance and viewer metrics

WAVE - Enterprise Live Streaming Platform