Skip to main content

Consuming Configuration Updates

protoconf provides a gRPC service that allows your application to subscribe to configuration updates. This service is provided by the protoconf agent, which can run in development mode and listen on 0.0.0.0:4300.

This guide will walk you through how to subscribe to configuration updates using the protoconf agent in various languages: Go, Python, Node.js, Rust, and Java.

protoconf Agent

To start the protoconf agent in development mode, use the following command:

protoconf agent -dev .

The protoconf agent implements the following gRPC service:

syntax = "proto3";
package v1;

option java_package = "com.protoconf.agent.api.v1";

import "google/protobuf/any.proto";

message ConfigSubscriptionRequest {
    string path = 1;
}

message ConfigUpdate {
    google.protobuf.Any value = 1;
}

service ProtoconfService{
    rpc SubscribeForConfig(ConfigSubscriptionRequest) returns (stream ConfigUpdate);
}

You can use it as a dependency from buf: buf.build/protoconf/protoconf.

Code Generation

Before consuming the configuration updates, you need to generate code from the proto file. A simple solution for this is using buf. Here is the content for buf.yaml and buf.gen.yaml:

buf.yaml:

version: v1
name: buf.build/myusername/myrepository
deps:
  - buf.build/protoconf/protoconf

buf.gen.yaml:

version: v1
plugins:
  - name: go
    out: gen/go
  - name: java
    out: gen/java
  - name: node
    out: gen/js
  - name: python
    out: gen/python

With the above configurations, run buf generate to generate the code for your protobuf files. Now you can consume the configuration updates in your preferred language.

In Go, use the grpc package to create a client and subscribe to configuration updates:

package main

import (
    "context"
    "log"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "github.com/golang/protobuf/ptypes"
    pb "gen/go/protoconf/v1"
    mypb "gen/go/myproject/v1"
)

func main() {
    conn, err := grpc.Dial("localhost:4300", grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer conn.Close()

    client := pb.NewProtoconfServiceClient(conn)

    stream, err := client.SubscribeForConfig(context.Background(), &pb.ConfigSubscriptionRequest{
        Path: "myproject/server_config",
    })
    if err != nil {
        log.Fatalf("Failed to subscribe for config: %v", err)
    }

    for {
        configUpdate, err := stream.Recv()
        if err != nil {
            log.Fatalf("Error receiving config update: %v", err)
        }

        var config mypb.ServerConfiguration
        if err := ptypes.UnmarshalAny(configUpdate.Value, &config); err != nil {
            log.Fatalf("Failed to unmarshal config update: %v", err)
        }

        log.Printf("Received config update: %+v", config)
    }
}

In this example, the SubscribeForConfig RPC is used to subscribe for updates to the myproject/server_config configuration. The received ConfigUpdate messages are unpacked into ServerConfiguration objects which can then be used by your application.

These examples provide a starting point for integrating protoconf into your applications. As you adapt these examples to your specific needs, you may find additional resources on the gRPC, protobuf, and protoconf libraries helpful.