blob: 076e1b8b2cfa6c0a59ada086f5b74fb233bd1725 [file] [view]
---
id: functions-quickstart
title: Getting started with Pulsar Functions
sidebar_label: "Get started"
description: Get started to create and validate Pulsar functions.
---
This hands-on tutorial provides step-by-step instructions and examples on how to create and validate functions in a [standalone Pulsar](getting-started-standalone.md), including stateful functions and window functions.
## Prerequisites
- JDK 8+. For more details, refer to [Pulsar runtime Java version recommendation](https://github.com/apache/pulsar#pulsar-runtime-java-version-recommendation).
- Windows OS is not supported.
## Step 1: Start standalone Pulsar
1. Enable pulsar function in `conf/standalone.conf` (add this field if not exists):
```properties
functionsWorkerEnabled=true
```
2. Start Pulsar locally.
```bash
bin/pulsar standalone
```
All the components (including ZooKeeper, BookKeeper, broker, and so on) of a Pulsar service start in order. You can use the `bin/pulsar-admin brokers healthcheck` command to make sure the Pulsar service is up and running.
3. Check the Pulsar binary protocol port.
```bash
telnet localhost 6650
```
4. Check the Pulsar Function cluster.
```bash
bin/pulsar-admin functions-worker get-cluster
```
**Output**
```json
[{"workerId":"c-standalone-fw-localhost-6750","workerHostname":"localhost","port":6750}]
```
5. Make sure a public tenant exists.
```bash
bin/pulsar-admin tenants list
```
**Output**
```text
public
```
6. Make sure a default namespace exists.
```bash
bin/pulsar-admin namespaces list public
```
**Output**
```text
public/default
```
7. Make sure the table service is enabled successfully.
```bash
telnet localhost 4181
```
**Output**
```text
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
```
## Step 2: Create a namespace for test
1. Create a tenant and a namespace.
```bash
bin/pulsar-admin tenants create test
bin/pulsar-admin namespaces create test/test-namespace
```
2. In the same terminal window as step 1, verify the tenant and the namespace.
```bash
bin/pulsar-admin namespaces list test
```
**Output**
This output shows that both tenant and namespace are created successfully.
```text
"test/test-namespace"
```
## Step 3: Start functions
:::note
Before starting functions, you need to [start Pulsar](#start-standalone-pulsar) and [create a test namespace](#create-a-namespace-for-test).
:::
1. Create a function named `examples`.
:::tip
You can see both the `example-function-config.yaml` and `api-examples.jar` files under the `examples` folder of the Pulsar's directory on your local machine.
This example function will add a `!` at the end of every message.
:::
```bash
bin/pulsar-admin functions create \
--function-config-file $PWD/examples/example-function-config.yaml \
--jar $PWD/examples/api-examples.jar
```
**Output**
```text
Created Successfully
```
You can check the config of this function in `examples/example-function-config.yaml`:
```yaml
tenant: "test"
namespace: "test-namespace"
name: "example" # function name
className: "org.apache.pulsar.functions.api.examples.ExclamationFunction"
inputs: ["test_src"] # this function will read messages from these topics
output: "test_result" # the return value of this function will be sent to this topic
autoAck: true # function will acknowledge input messages if set true
parallelism: 1
```
You can see the [source code](https://github.com/apache/pulsar/blob/master/pulsar-functions/java-examples/src/main/java/org/apache/pulsar/functions/api/examples/ExclamationFunction.java) of `ExclamationFunction`.
For more information about the yaml config, see the [reference](functions-cli.md#yaml-configurations-for-pulsar-functions).
2. In the same terminal window as step 1, verify the function's configurations.
```bash
bin/pulsar-admin functions get \
--tenant test \
--namespace test-namespace \
--name example
```
**Output**
```json
{
"tenant": "test",
"namespace": "test-namespace",
"name": "example",
"className": "org.apache.pulsar.functions.api.examples.ExclamationFunction",
"inputSpecs": {
"test_src": {
"isRegexPattern": false,
"schemaProperties": {},
"consumerProperties": {},
"poolMessages": false
}
},
"output": "test_result",
"producerConfig": {
"useThreadLocalProducers": false,
"batchBuilder": ""
},
"processingGuarantees": "ATLEAST_ONCE",
"retainOrdering": false,
"retainKeyOrdering": false,
"forwardSourceMessageProperty": true,
"userConfig": {},
"runtime": "JAVA",
"autoAck": true,
"parallelism": 1,
"resources": {
"cpu": 1.0,
"ram": 1073741824,
"disk": 10737418240
},
"cleanupSubscription": true,
"subscriptionPosition": "Latest"
}
```
3. In the same terminal window as step 1, verify the function's status.
```bash
bin/pulsar-admin functions status \
--tenant test \
--namespace test-namespace \
--name example
```
**Output**
`"running": true` shows that the function is running.
```json
{
"numInstances" : 1,
"numRunning" : 1,
"instances" : [ {
"instanceId" : 0,
"status" : {
"running" : true,
"error" : "",
"numRestarts" : 0,
"numReceived" : 0,
"numSuccessfullyProcessed" : 0,
"numUserExceptions" : 0,
"latestUserExceptions" : [ ],
"numSystemExceptions" : 0,
"latestSystemExceptions" : [ ],
"averageLatency" : 0.0,
"lastInvocationTime" : 0,
"workerId" : "c-standalone-fw-localhost-8080"
}
} ]
}
```
4. In the same terminal window as step 1, subscribe to the **output topic** `test_result`.
```bash
bin/pulsar-client consume -s test-sub -n 0 test_result
```
5. In a new terminal window, produce messages to the **input topic** `test_src`.
```bash
bin/pulsar-client produce -m "test-messages-`date`" -n 10 test_src
```
6. In the same terminal window as step 1, the messages produced by the `example` function are returned. You can see there is a `!` added at the end of every message.
**Output**
```text
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
----- got message -----
test-messages-Thu Jul 19 11:59:15 PDT 2021!
```
### Start stateful functions
The standalone mode of Pulsar enables BookKeeper table service for stateful functions. For more information, see [Configure state storage](functions-develop-state.md).
:::note
Before starting stateful functions, you need to [start Pulsar](#start-standalone-pulsar) and [create a test namespace](#create-a-namespace-for-test).
:::
The following example provides instructions to start a stateful function to validate counter functions.
1. Create a function using `examples/example-stateful-function-config.yaml`.
```bash
bin/pulsar-admin functions create \
--function-config-file $PWD/examples/example-stateful-function-config.yaml \
--jar $PWD/examples/api-examples.jar
```
**Output**
```text
Created Successfully
```
You can check the config of this function in `examples/example-stateful-function-config.yaml`:
```yaml
tenant: "test"
namespace: "test-namespace"
name: "word_count"
className: "org.apache.pulsar.functions.api.examples.WordCountFunction"
inputs: ["test_wordcount_src"] # this function will read messages from these topics
autoAck: true
parallelism: 1
```
You can see the [source code](https://github.com/apache/pulsar/blob/master/pulsar-functions/java-examples/src/main/java/org/apache/pulsar/functions/api/examples/WordCountFunction.java) of `WordCountFunction`. This function won't return any value but store the occurrence of words in function context. So you don't need to specify an output topic.
For more information about the yaml config, see the [reference](functions-cli.md#yaml-configurations-for-pulsar-functions).
2. In the same terminal window as step 1, get the information of the `word_count` function.
```bash
bin/pulsar-admin functions get \
--tenant test \
--namespace test-namespace \
--name word_count
```
**Output**
```json
{
"tenant": "test",
"namespace": "test-namespace",
"name": "word_count",
"className": "org.apache.pulsar.functions.api.examples.WordCountFunction",
"inputSpecs": {
"test_wordcount_src": {
"isRegexPattern": false,
"schemaProperties": {},
"consumerProperties": {},
"poolMessages": false
}
},
"producerConfig": {
"useThreadLocalProducers": false,
"batchBuilder": ""
},
"processingGuarantees": "ATLEAST_ONCE",
"retainOrdering": false,
"retainKeyOrdering": false,
"forwardSourceMessageProperty": true,
"userConfig": {},
"runtime": "JAVA",
"autoAck": true,
"parallelism": 1,
"resources": {
"cpu": 1.0,
"ram": 1073741824,
"disk": 10737418240
},
"cleanupSubscription": true,
"subscriptionPosition": "Latest"
}
```
3. In the same terminal window as step 1, get the status of the `word_count` function.
```bash
bin/pulsar-admin functions status \
--tenant test \
--namespace test-namespace \
--name word_count
```
**Output**
```json
{
"numInstances" : 1,
"numRunning" : 1,
"instances" : [ {
"instanceId" : 0,
"status" : {
"running" : true,
"error" : "",
"numRestarts" : 0,
"numReceived" : 0,
"numSuccessfullyProcessed" : 0,
"numUserExceptions" : 0,
"latestUserExceptions" : [ ],
"numSystemExceptions" : 0,
"latestSystemExceptions" : [ ],
"averageLatency" : 0.0,
"lastInvocationTime" : 0,
"workerId" : "c-standalone-fw-localhost-8080"
}
} ]
}
```
4. In the same terminal window as step 1, query the state table for the function with the key `hello`. This operation watches the changes associated with `hello`.
```bash
bin/pulsar-admin functions querystate \
--tenant test \
--namespace test-namespace \
--name word_count -k hello -w
```
:::tip
For more information about the `pulsar-admin functions querystate options` command, including flags, descriptions, default values, and shorthands, see [Pulsar admin API](/reference/#/@pulsar:version_reference@/pulsar-admin/).
:::
**Output**
```text
key 'hello' doesn't exist.
key 'hello' doesn't exist.
key 'hello' doesn't exist.
...
```
5. In a new terminal window, produce 10 messages with `hello` to the **input topic** `test_wordcount_src` using one of the following methods. The value of `hello` is updated to 10.
```bash
bin/pulsar-client produce -m "hello" -n 10 test_wordcount_src
```
6. In the same terminal window as step 1, check the result.
The result shows that the **output topic** `test_wordcount_dest` receives the messages.
**Output**
```json
{
"key": "hello",
"numberValue": 10,
"version": 9
}
```
7. In the terminal window as step 5, produce another 10 messages with `hello`. The value of `hello` is updated to 20.
```bash
bin/pulsar-client produce -m "hello" -n 10 test_wordcount_src
```
8. In the same terminal window as step 1, check the result.
The result shows that the **output topic** `test_wordcount_dest` receives the value of 20.
```json
{
"key": "hello",
"numberValue": 20,
"version": 19
}
```
### Start window functions
Window functions are a special form of Pulsar Functions. For more information, see [concepts](functions-concepts.md#window-function).
:::note
Before starting window functions, you need to [start Pulsar](#start-standalone-pulsar) and [create a test namespace](#create-a-namespace-for-test).
:::
The following example provides instructions to start a window function to calculate the sum in a window.
1. Create a function using `example-window-function-config.yaml`.
```bash
bin/pulsar-admin functions create \
--function-config-file $PWD/examples/example-window-function-config.yaml \
--jar $PWD/examples/api-examples.jar
```
**Output**
```text
Created Successfully
```
You can check the config of this function in `examples/example-window-function-config.yaml`:
```yaml
tenant: "test"
namespace: "test-namespace"
name: "window-example"
className: "org.apache.pulsar.functions.api.examples.AddWindowFunction"
inputs: ["test_window_src"]
output: "test_window_result"
autoAck: true
parallelism: 1
# every 5 messages, calculate sum of the latest 10 messages
windowConfig:
windowLengthCount: 10
slidingIntervalCount: 5
```
You can see the source code of `AddWindowFunction` [here](https://github.com/apache/pulsar/blob/master/pulsar-functions/java-examples/src/main/java/org/apache/pulsar/functions/api/examples/AddWindowFunction.java).
For more information about the yaml config, see the [reference](functions-cli.md#yaml-configurations-for-pulsar-functions).
2. In the same terminal window as step 1, verify the function's configurations.
```bash
bin/pulsar-admin functions get \
--tenant test \
--namespace test-namespace \
--name window-example
```
**Output**
```json
{
"tenant": "test",
"namespace": "test-namespace",
"name": "window-example",
"className": "org.apache.pulsar.functions.api.examples.AddWindowFunction",
"inputSpecs": {
"test_window_src": {
"isRegexPattern": false,
"schemaProperties": {},
"consumerProperties": {},
"poolMessages": false
}
},
"output": "test_window_result",
"producerConfig": {
"useThreadLocalProducers": false,
"batchBuilder": ""
},
"processingGuarantees": "ATLEAST_ONCE",
"retainOrdering": false,
"retainKeyOrdering": false,
"forwardSourceMessageProperty": true,
"userConfig": {},
"runtime": "JAVA",
"autoAck": false,
"parallelism": 1,
"resources": {
"cpu": 1.0,
"ram": 1073741824,
"disk": 10737418240
},
"windowConfig": {
"windowLengthCount": 10,
"slidingIntervalCount": 5,
"actualWindowFunctionClassName": "org.apache.pulsar.functions.api.examples.AddWindowFunction",
"processingGuarantees": "ATLEAST_ONCE"
},
"cleanupSubscription": true,
"subscriptionPosition": "Latest"
}
```
3. In the same terminal window as step 1, verify the function's status.
```bash
bin/pulsar-admin functions status \
--tenant test \
--namespace test-namespace \
--name window-example
```
**Output**
`"running": true` shows that the function is running.
```json
{
"numInstances" : 1,
"numRunning" : 1,
"instances" : [ {
"instanceId" : 0,
"status" : {
"running" : true,
"error" : "",
"numRestarts" : 0,
"numReceived" : 0,
"numSuccessfullyProcessed" : 0,
"numUserExceptions" : 0,
"latestUserExceptions" : [ ],
"numSystemExceptions" : 0,
"latestSystemExceptions" : [ ],
"averageLatency" : 0.0,
"lastInvocationTime" : 0,
"workerId" : "c-standalone-fw-localhost-8080"
}
} ]
}
```
4. In the same terminal window as step 1, subscribe to the **output topic** `test_window_result`.
```bash
bin/pulsar-client consume -s test-sub -n 0 test_window_result
```
5. In a new terminal window, produce messages to the **input topic** `test_window_src`.
```bash
bin/pulsar-client produce -m "3" -n 10 test_window_src
```
6. In the same terminal window as step 1, the messages produced by the window function `window-example` are returned.
**Output**
```text
----- got message -----
key:[null], properties:[], content:15
----- got message -----
key:[null], properties:[], content:30
```