Serverless and Segment, a Match Made in Data Heaven

Trevor Heath

Trevor Heath

VP of Product Development • 5 min read

Serverless and Segment, a Match Made in Data Heaven

In a world where data is king, it has become more and more critical that your company thinks about tracking and analytics the same way it thinks about frontend applications and backend infrastructure.

Our team has adopted a consistent, safe and modular way to track user, admin and programmatic events on the server side using Serverless, event driven architecture and Segment.io.  This convention allows us to move fast without requiring repeated changes to any of the code core to the business.  It's a data team's dream to iterate on tracking without redeploying any critical path backend or frontend code.  Let's break down how Serverless and Segment work together to create a modular and flexible data pipeline.

SERVERLESS -

https://serverless.com/

A platform for event-driven architecture.

We use AWS lambda function as our foundation for Serverless.  With our event gateway we are able to listen for events emitted by any other server or frontend client.  These events can then trigger modular and self-contained lambda functions.  Event-driven architecture provides a safe and quick way to add functionality while limiting exposure to critical bugs.

SEGMENT

http://segment.io/

‍ An analytics service that acts as a single API for all of your team's data sources and destinations.

Segment allows you to track an event or identify a user with a consistent piece of code and send that information to pre-integrated data platforms where it can be best analyzed.  This flexibility allows development teams, marketers and data analysts to manipulate with data independently without blockers.

Emit an event once from the API, frontend or another lambda function

try {
  const input = args.data;
  const user: User = context.currentUser as User;
  const backgroundCheck = await startBackgroundCheck({ user, id})
  context.eventGateway.emit({
    event: 'driver.bgcApplied',
    data: { driverld: user.driver.id }
  })
    return {
      code: ResponseCodes.OK,
      success: true,
      message: null,
      backgroundCheck
  }
} catch (e) {
    return {
      code: ResponseCodes.REQUEST_FAILED,
      success: false,
      message: e.message,
      backgroundCheck: null
    }
  }

Pass the appropriate data and event name.

context.eventGateway.emit({
  event: ldriver.bgcApplied1,
  data: { driverld: user.driver.id },
});

Now when the event is triggered you can listen and invoke Serverless functions that will handle the event tracking utilizing Segment from your event gateway.  Broad events like database updates are good way to reduce the amount of code necessary in your API.  You can even handle this entirely from your event gateway by using the serverless-event-gateway-plugin which allows you to listen for webhooks from your database or other third party services (Database updates, chat apis, CRMs, ect.)

You can define these in your serverless.yml file but be aware there is a restriction to the number events you will be able add to it.  Check out this article by my colleague to learn about a micro-service architecture which allows you to split your code in separate services.

driverBgcApplied:
  handler: src/trackDriverBgc.handler
  events:
    - eventgateway:
        event: "driver.bgcApplied"

driverBgcRejected:
  handler: src/trackDriverBgc.handler
    events:
      - eventgateway:
        event: "driver.bgcRejected"

// Events triggered by Webhooks
webhookDbSubscription:
  handler: src/dbSubscription.handler
    events:
      - eventgateway:
          type: async
          eventType: http.request
          path: /webhooks/dbSubscription
          method: POST
  1. Now handle the event and fire an event using Segment's API! You even have a chance to query your database to collect relevant information before.

import { responses, hyrecarGraphql } from "@packages/utils/src";
import segmentClient from './segmentClient';
export async function handler(event, context, callback) {
    const data = event.data;
    console.log(`Received ${event.eventType} event with data:`);
    console.dir(data);
    try {
        trackDriverApplication(event.eventType, data)
        return callback(null, responses.success())
    } catch (e) {
        console.error(e);
        return callback(responses.error(JSON.stringify(e)));
    }
}
async function trackDriverApplication(eventType: string, data: { driverId: string }) {
    const user = await getUserDetails(data.driverId)
    const track = await getTrackName(eventType)
    segmentClient.track({
        event: track,
        userId: <user.id>,
        properties: {
            driverId: data.driverId
        }
    }, () => console.log("Success"));
}
async function getTrackName(eventType: string) {
    let trackName
    switch (eventType) {
        case "driver.bgcApproved":
            trackName = "DRIVER_VERIFICATION_APPROVED"
            break
        case "driver.bgcRejected":
            trackName = "DRIVER_VERIFICATION_REJECTED"
            break
        case "driver.bgcApplied":
            trackName = "DRIVER_VERIFICATION_APPLIED"
            break
        default:
            break
    }
    return trackName;
}
export async function getUserDetails(driverId): Promise<any> {
    const query = `query DriverDetails($driverId: ID!){
        driver(where: {id: $driverId}) {
            id
            user {
                id
            }
        }
    }`;
    const user = (await hyrecarGraphql({ query, variables: { driverId } })).data
        .driver.user;
    return user;
}

Wohooo! Now you will receive the events in Segment.  With a few clicks, you can easily configure Segment to pass that data on to the analytic tools you love to use!

This is a quick overview of the workflow we take to implement tracking with Serverless and Segment.  The power is really harnessed when all of the events you need have been emitted properly and you are taking advantage of database webhooks to capture changes to user information.  If the emitted events pass the proper contextual information like IDs it makes it really easy to add and change your Segment events without ever needing to dive back into the API handling your core business logic!

Work faster, worry less.