Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating SDK, adding OpenTelemetry #33

Merged
merged 8 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ $ docker-compose exec app rr workers -i
```

## Local Setup
**1. Make sure you have PHP 7.4, or higher, installed.**
**1. Make sure you have PHP 8.1, or higher, installed.**

**2. Clone this repo and change directory into the root of the project.**

Expand Down Expand Up @@ -69,7 +69,7 @@ $ composer install

**5. Download RoadRunner application server**

The Temporal PHP SDK requires the RoadRunner 2.0 application server and supervisor to run Activities and Workflows in a scalable way.
The Temporal PHP SDK requires the RoadRunner v2023.2 application server and supervisor to run Activities and Workflows in a scalable way.

```bash
$ cd app
Expand All @@ -85,10 +85,7 @@ The fastest way to do that is by following the [Quick install guide](https://doc

You can also run the included `docker-compose.yml` file. Make sure to comment `app` section.

**7. Update configuration**
Make sure to update the temporal address in `app/.rr.yaml` to `localhost:7233`.

**8. Start the application using RoadRunner**
**7. Start the application using RoadRunner**

By default, all samples run using a single RoadRunner Server instance.
To start the application using RoadRunner:
Expand All @@ -102,7 +99,7 @@ You can now interact with the samples.

Note: You can alter number of PHP Workers in `app/.rr.yaml`.

**9. Run a sample**
**8. Run a sample**

## Samples

Expand Down
14 changes: 12 additions & 2 deletions app/.rr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ server:
command: "php worker.php"

temporal:
address: "127.0.0.1:7233"
address: ${TEMPORAL_HOST:-localhost}:${TEMPORAL_PORT:-7233}
activities:
num_workers: 4

service:
interceptors:
command: "./rr serve -c ./src/Interceptors/.rr.yaml"
command: "${INTERCEPTORS_RR_PATH:-./rr} serve -c ./src/Interceptors/.rr.yaml"

logs:
level: info
mode: development

otel:
insecure: true
compress: false
client: http
exporter: otlp
resource:
service_name: rr-temporal-samples
service_version: 1.0.0
endpoint: ${OTEL_HOST:-localhost}:${OTEL_PORT:-4318}
5 changes: 1 addition & 4 deletions app/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

use Temporal\SampleUtils\DeclarationLocator;
use Temporal\Client\GRPC\ServiceClient;
use Temporal\Client\WorkflowClient;
use Symfony\Component\Console\Application;
use Temporal\SampleUtils\Command;

Expand All @@ -25,12 +24,10 @@
$host = 'localhost:7233';
}

$workflowClient = WorkflowClient::create(ServiceClient::create($host));

$app = new Application('Temporal PHP-SDK Samples');

foreach ($declarations->getCommands() as $command) {
$app->add(Command::create($command, $workflowClient));
$app->add(Command::create($command, ServiceClient::create($host)));
}

$app->run();
12 changes: 10 additions & 2 deletions app/composer.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
{
"minimum-stability": "beta",
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"temporal/sdk": ">=2.7.0",
"spiral/tokenizer": ">=2.7"
"spiral/tokenizer": "^3.7",
"temporal/open-telemetry-interceptors": "dev-master",
"open-telemetry/exporter-otlp": "^0.0.17",
"open-telemetry/transport-grpc": "^0.0.17"
},
"autoload": {
"psr-4": {
"Temporal\\Samples\\": "src",
"Temporal\\SampleUtils\\": "util-src"
}
},
"config": {
"allow-plugins": {
"php-http/discovery": true
}
}
}
2 changes: 1 addition & 1 deletion app/src/Interceptors/.rr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ server:
- TEMPORAL_CLI_ADDRESS: temporal:7233

temporal:
address: "temporal:7233"
address: ${TEMPORAL_HOST:-localhost}:${TEMPORAL_PORT:-7233}
activities:
num_workers: 2

Expand Down
27 changes: 16 additions & 11 deletions app/util-src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@

namespace Temporal\SampleUtils;

use Temporal\Client\GRPC\ServiceClient;
use Temporal\Client\WorkflowClient;
use Temporal\Client\WorkflowClientInterface;
use Temporal\Interceptor\SimplePipelineProvider;
use Temporal\OpenTelemetry\Interceptor\OpenTelemetryWorkflowClientCallsInterceptor;

class Command extends \Symfony\Component\Console\Command\Command
{
Expand All @@ -21,27 +25,29 @@ class Command extends \Symfony\Component\Console\Command\Command
// Short command description.
protected const DESCRIPTION = '';

// Command options specified in Symphony format. For more complex definitions redefine
// Command options specified in Symfony format. For more complex definitions redefine
// getOptions() method.
protected const OPTIONS = [];

// Command arguments specified in Symphony format. For more complex definitions redefine
// Command arguments specified in Symfony format. For more complex definitions redefine
// getArguments() method.
protected const ARGUMENTS = [];

/**
* @var WorkflowClientInterface
*/
protected WorkflowClientInterface $workflowClient;

/**
* Command constructor.
* @param WorkflowClientInterface $workflowClient
*/
public function __construct(WorkflowClientInterface $workflowClient)
public function __construct(ServiceClient $serviceClient)
{
parent::__construct();
$this->workflowClient = $workflowClient;

$this->workflowClient = WorkflowClient::create(
serviceClient: $serviceClient,
interceptorProvider: new SimplePipelineProvider([
new OpenTelemetryWorkflowClientCallsInterceptor(TracerFactory::create('interceptors-sample-client')),
])
);
}

/**
Expand Down Expand Up @@ -83,11 +89,10 @@ protected function defineArguments(): array

/**
* @param string $class
* @param WorkflowClientInterface $workflowClient
* @return static
*/
public static function create(string $class, WorkflowClientInterface $workflowClient): self
public static function create(string $class, ServiceClient $client): self
{
return new $class($workflowClient);
return new $class($client);
}
}
51 changes: 51 additions & 0 deletions app/util-src/TracerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/**
* This file is part of Temporal package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Temporal\SampleUtils;

use OpenTelemetry\API\Common\Signal\Signals;
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use OpenTelemetry\Contrib\Grpc\GrpcTransportFactory;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SemConv\ResourceAttributes;
use Temporal\OpenTelemetry\Tracer;
use OpenTelemetry\SDK\Trace\SpanProcessorFactory;
use OpenTelemetry\SDK\Trace\TracerProvider;

final class TracerFactory
{
public static function create(string $serviceName): Tracer
{
$endpoint = getenv('OTEL_COLLECTOR_ENDPOINT');
if (empty($endpoint)) {
$endpoint = 'http://collector:4317';
}

$transport = (new GrpcTransportFactory())->create($endpoint . OtlpUtil::method(Signals::TRACE));
$spanProcessor = (new SpanProcessorFactory())->create(new SpanExporter($transport));

$resource = ResourceInfoFactory::merge(
ResourceInfo::create(Attributes::create([
ResourceAttributes::SERVICE_NAME => $serviceName,
])),
ResourceInfoFactory::defaultResource(),
);

return new Tracer(
(new TracerProvider(spanProcessors: $spanProcessor, resource: $resource))->getTracer('Temporal Samples'),
TraceContextPropagator::getInstance()
);
}
}
12 changes: 11 additions & 1 deletion app/worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@

declare(strict_types=1);

use Temporal\Interceptor\SimplePipelineProvider;
use Temporal\OpenTelemetry\Interceptor\OpenTelemetryActivityInboundInterceptor;
use Temporal\OpenTelemetry\Interceptor\OpenTelemetryWorkflowOutboundRequestInterceptor;
use Temporal\SampleUtils\DeclarationLocator;
use Temporal\SampleUtils\TracerFactory;
use Temporal\WorkerFactory;
use Temporal\Samples\FileProcessing;

Expand All @@ -22,8 +26,14 @@
// factory initiates and runs task queue specific activity and workflow workers
$factory = WorkerFactory::create();

// OpenTelemetry tracer
$tracer = TracerFactory::create('interceptors-sample-worker');

// Worker that listens on a task queue and hosts both workflow and activity implementations.
$worker = $factory->newWorker();
$worker = $factory->newWorker(interceptorProvider: new SimplePipelineProvider([
new OpenTelemetryActivityInboundInterceptor($tracer),
new OpenTelemetryWorkflowOutboundRequestInterceptor($tracer)
]));

foreach ($declarations->getWorkflowTypes() as $workflowType) {
// Workflows are stateful. So you need a type to create instances.
Expand Down
37 changes: 33 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,46 @@ services:
ports:
- 8080:8080

collector:
container_name: collector
image: otel/opentelemetry-collector-contrib:0.79.0
networks:
- temporal-network
command: [ "--config=/etc/otel-collector-config.yml" ]
ports:
- 4317:4317
- 4318:4318
volumes:
- ./docker/otel/otel-collector-config.yml:/etc/otel-collector-config.yml

zipkin:
container_name: zipkin
image: openzipkin/zipkin-slim
networks:
- temporal-network
ports:
- 9411:9411

app:
build: .
# volumes:
# - ./app:/var/app
build:
dockerfile: docker/app/Dockerfile
context: ./
# volumes:
# - ./app:/var/app
depends_on:
- temporal
networks:
- temporal-network
environment:
- "TEMPORAL_CLI_ADDRESS=temporal:7233"
- TEMPORAL_CLI_ADDRESS=temporal:7233
- TELEMETRY_DRIVER=otel
- OTEL_TRACES_EXPORTER=otlp
- OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
- OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318
- OTEL_PHP_TRACES_PROCESSOR=simple
- TEMPORAL_HOST=temporal
- OTEL_HOST=collector
- INTERCEPTORS_RR_PATH=/usr/local/bin/rr
command: [ "/usr/local/bin/wait-for-temporal.sh", "temporal", "/usr/local/bin/rr", "serve", "-c", "/var/app/.rr.yaml" ]

networks:
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile → docker/app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM php:8.0.15-cli
FROM php:8.2.7-cli

RUN apt-get update && apt-get install -y --no-install-recommends \
nano \
Expand All @@ -14,7 +14,7 @@ RUN docker-php-ext-install zip \
&& docker-php-ext-enable opcache sockets mbstring

# Protobuf and GRPC
ENV PROTOBUF_VERSION "3.19.2"
ENV PROTOBUF_VERSION "3.20.1"
RUN pecl channel-update pecl.php.net
RUN pecl install protobuf-${PROTOBUF_VERSION} grpc \
&& docker-php-ext-enable protobuf grpc
Expand Down
23 changes: 23 additions & 0 deletions docker/otel/otel-collector-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
receivers:
otlp:
protocols:
grpc:
http:

processors:
batch:
timeout: 1s

exporters:
logging:
loglevel: debug

zipkin:
endpoint: "http://zipkin:9411/api/v2/spans"

service:
pipelines:
traces:
receivers: [ otlp ]
processors: [ batch ]
exporters: [ zipkin ]