blob: 014d9e81a00dba0cad000c07cbb3d582e9416433 [file] [log] [blame]
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Getting started with Pulsar Functions · Apache Pulsar</title><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="generator" content="Docusaurus"/><meta name="description" content="This tutorial will walk you through running a [standalone](/docs/en/2.3.1/reference-terminology#standalone) Pulsar [cluster](/docs/en/2.3.1/reference-terminology#cluster) on your machine and then running your first Pulsar Functions using that cluster. The first function will run in local run mode (outside your Pulsar [cluster](/docs/en/2.3.1/reference-terminology#cluster)), while the second will run in cluster mode (inside your cluster)."/><meta name="docsearch:version" content="2.3.1"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Getting started with Pulsar Functions · Apache Pulsar"/><meta property="og:type" content="website"/><meta property="og:url" content="https://pulsar.apache.org/"/><meta property="og:description" content="This tutorial will walk you through running a [standalone](/docs/en/2.3.1/reference-terminology#standalone) Pulsar [cluster](/docs/en/2.3.1/reference-terminology#cluster) on your machine and then running your first Pulsar Functions using that cluster. The first function will run in local run mode (outside your Pulsar [cluster](/docs/en/2.3.1/reference-terminology#cluster)), while the second will run in cluster mode (inside your cluster)."/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://pulsar.apache.org/img/pulsar.svg"/><link rel="shortcut icon" href="/img/pulsar.ico"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css"/><link rel="alternate" type="application/atom+xml" href="https://pulsar.apache.org/blog/atom.xml" title="Apache Pulsar Blog ATOM Feed"/><link rel="alternate" type="application/rss+xml" href="https://pulsar.apache.org/blog/feed.xml" title="Apache Pulsar Blog RSS Feed"/><link rel="stylesheet" href="/css/code-blocks-buttons.css"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script><script type="text/javascript" src="/js/custom.js"></script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/en"><img class="logo" src="/img/pulsar.svg" alt="Apache Pulsar"/></a><a href="/en/versions"><h3>2.3.1</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/en/2.3.1/getting-started-standalone" target="_self">Docs</a></li><li class=""><a href="/en/download" target="_self">Download</a></li><li class="siteNavGroupActive"><a href="/docs/en/2.3.1/client-libraries" target="_self">Clients</a></li><li class=""><a href="#restapis" target="_self">REST APIs</a></li><li class=""><a href="#cli" target="_self">Cli</a></li><li class=""><a href="/blog/" target="_self">Blog</a></li><li class=""><a href="#community" target="_self">Community</a></li><li class=""><a href="#apache" target="_self">Apache</a></li><li class=""><a href="https://pulsar-next.staged.apache.org/" target="_self">New Website (Beta)</a></li><span><li><a id="languages-menu" href="#"><img class="languages-icon" src="/img/language.svg" alt="Languages icon"/>English</a><div id="languages-dropdown" class="hide"><ul id="languages-dropdown-items"><li><a href="/docs/ja/2.3.1/functions-quickstart">日本語</a></li><li><a href="/docs/fr/2.3.1/functions-quickstart">Français</a></li><li><a href="/docs/ko/2.3.1/functions-quickstart">한국어</a></li><li><a href="/docs/zh-CN/2.3.1/functions-quickstart">中文</a></li><li><a href="/docs/zh-TW/2.3.1/functions-quickstart">繁體中文</a></li><li><a href="https://crowdin.com/project/apache-pulsar" target="_blank" rel="noreferrer noopener">Help Translate</a></li></ul></div></li><script>
const languagesMenuItem = document.getElementById("languages-menu");
const languagesDropDown = document.getElementById("languages-dropdown");
languagesMenuItem.addEventListener("click", function(event) {
event.preventDefault();
if (languagesDropDown.className == "hide") {
languagesDropDown.className = "visible";
} else {
languagesDropDown.className = "hide";
}
});
</script></span></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i></i><span>Pulsar Functions</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/pulsar-2.0">Pulsar 2.0</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/getting-started-standalone">Run Pulsar locally</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/getting-started-docker">Pulsar in Docker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/client-libraries">Client libraries</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Concepts and Architecture</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-messaging">Messaging</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-architecture-overview">Architecture</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-clients">Clients</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-replication">Geo Replication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-multi-tenancy">Multi Tenancy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-authentication">Authentication and Authorization</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-topic-compaction">Topic Compaction</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-tiered-storage">Tiered Storage</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/concepts-schema-registry">Schema Registry</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar Functions</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/functions-overview">Overview</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/en/2.3.1/functions-quickstart">Getting started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/functions-api">API</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/functions-deploying">Deploying functions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/functions-guarantees">Processing guarantees</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/functions-state">State Storage</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/functions-metrics">Metrics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/window-functions-context">Window Functions: Context</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar IO</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/io-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/io-quickstart">Getting started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/io-managing">Managing Connectors</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/io-connectors">Builtin Connectors</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/io-develop">Developing Connectors</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/io-cdc">CDC Connector</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar SQL</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/sql-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/sql-getting-started">Getting Started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/sql-deployment-configurations">Deployment and Configuration</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Deployment</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/deploy-aws">Amazon Web Services</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/deploy-kubernetes">Kubernetes</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/deploy-bare-metal">Bare metal</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/deploy-bare-metal-multi-cluster">Bare metal multi-cluster</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/deploy-monitoring">Monitoring</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Administration</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/administration-zk-bk">ZooKeeper and BookKeeper</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/administration-geo">Geo-replication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/administration-dashboard">Dashboard</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/administration-stats">Pulsar statistics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/administration-load-balance">Load balance</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/administration-proxy">Pulsar proxy</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Security</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-tls-transport">Transport Encryption using TLS</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-tls-authentication">Authentication using TLS</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-token-client">Client Authentication using tokens</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-token-admin">Token authentication admin</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-athenz">Authentication using Athenz</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-authorization">Authorization and ACLs</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-encryption">End-to-End Encryption</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/security-extending">Extending</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Client Libraries</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/client-libraries-java">Java</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/client-libraries-go">Go</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/client-libraries-python">Python</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/client-libraries-cpp">C++</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/client-libraries-websocket">WebSocket</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Admin API</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-clusters">Clusters</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-tenants">Tenants</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-brokers">Brokers</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-namespaces">Namespaces</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-permissions">Permissions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-persistent-topics">Persistent topics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-non-persistent-topics">Non-Persistent topics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-partitioned-topics">Partitioned topics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/admin-api-schemas">Schemas</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Adaptors</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/adaptors-kafka">Kafka client wrapper</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/adaptors-spark">Apache Spark</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/adaptors-storm">Apache Storm</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Cookbooks</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-tiered-storage">Tiered Storage</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-compaction">Topic compaction</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-deduplication">Message deduplication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-non-persistent">Non-persistent messaging</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-partitioned">Partitioned Topics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-retention-expiry">Message retention and expiry</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-encryption">Encryption</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-message-queue">Message queue</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/cookbooks-bookkeepermetadata">BookKeeper Ledger Metadata</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Development</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/develop-tools">Simulation tools</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/developing-binary-protocol">Binary protocol</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/develop-schema">Custom schema storage</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/develop-load-manager">Modular load manager</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/develop-cpp">Building Pulsar C++ client</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Reference</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/reference-terminology">Terminology</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/reference-cli-tools">Pulsar CLI tools</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.3.1/reference-configuration">Pulsar configuration</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/apache/pulsar/edit/master/site2/docs/functions-quickstart.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Getting started with Pulsar Functions</h1></header><article><div><span><p>This tutorial will walk you through running a <a href="/docs/en/2.3.1/reference-terminology#standalone">standalone</a> Pulsar <a href="/docs/en/2.3.1/reference-terminology#cluster">cluster</a> on your machine and then running your first Pulsar Functions using that cluster. The first function will run in local run mode (outside your Pulsar <a href="/docs/en/2.3.1/reference-terminology#cluster">cluster</a>), while the second will run in cluster mode (inside your cluster).</p>
<blockquote>
<p>In local run mode, your Pulsar Function will communicate with your Pulsar cluster but will run outside of the cluster.</p>
</blockquote>
<h2><a class="anchor" aria-hidden="true" id="prerequisites"></a><a href="#prerequisites" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prerequisites</h2>
<p>In order to follow along with this tutorial, you'll need to have <a href="https://maven.apache.org/download.cgi">Maven</a> installed on your machine.</p>
<h2><a class="anchor" aria-hidden="true" id="run-a-standalone-pulsar-cluster"></a><a href="#run-a-standalone-pulsar-cluster" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Run a standalone Pulsar cluster</h2>
<p>In order to run our Pulsar Functions, we'll need to run a Pulsar cluster locally first. The easiest way to do that is to run Pulsar in <a href="/docs/en/2.3.1/reference-terminology#standalone">standalone</a> mode. Follow these steps to start up a standalone cluster:</p>
<pre><code class="hljs css language-bash">$ wget https://archive.apache.org/dist/pulsar/pulsar-2.3.1/apache-pulsar-2.3.1-bin.tar.gz
$ tar xvfz apache-pulsar-2.3.1-bin.tar.gz
$ <span class="hljs-built_in">cd</span> apache-pulsar-2.3.1
$ bin/pulsar standalone \
--advertised-address 127.0.0.1
</code></pre>
<p>When running Pulsar in standalone mode, the <code>public</code> tenant and <code>default</code> namespace will be created automatically for you. That tenant and namespace will be used throughout this tutorial.</p>
<h2><a class="anchor" aria-hidden="true" id="run-a-pulsar-function-in-local-run-mode"></a><a href="#run-a-pulsar-function-in-local-run-mode" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Run a Pulsar Function in local run mode</h2>
<p>Let's start with a simple function that takes a string as input from a Pulsar topic, adds an exclamation point to the end of the string, and then publishes that new string to another Pulsar topic. Here's the code for the function:</p>
<pre><code class="hljs css language-java"><span class="hljs-keyword">package</span> org.apache.pulsar.functions.api.examples;
<span class="hljs-keyword">import</span> java.util.function.Function;
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExclamationFunction</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Function</span>&lt;<span class="hljs-title">String</span>, <span class="hljs-title">String</span>&gt; </span>{
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">apply</span><span class="hljs-params">(String input)</span> </span>{
<span class="hljs-keyword">return</span> String.format(<span class="hljs-string">"%s!"</span>, input);
}
}
</code></pre>
<p>A JAR file containing this and several other functions (written in Java) is included with the binary distribution you downloaded above (in the <code>examples</code> folder). To run the function in local mode, i.e. on our laptop but outside our Pulsar cluster:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> localrun \
--jar examples/api-examples.jar \
--classname org.apache.pulsar.functions.api.examples.ExclamationFunction \
--inputs persistent://public/default/exclamation-input \
--output persistent://public/default/exclamation-output \
--name exclamation
</code></pre>
<blockquote>
<h4><a class="anchor" aria-hidden="true" id="multiple-input-topics-allowed"></a><a href="#multiple-input-topics-allowed" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Multiple input topics allowed</h4>
<p>In the example above, a single topic was specified using the <code>--inputs</code> flag. You can also specify multiple input topics as a comma-separated list using the same flag. Here's an example:</p>
<pre><code class="hljs css language-bash">--inputs topic1,topic2
</code></pre>
</blockquote>
<p>We can open up another shell and use the <a href="/docs/en/2.3.1/reference-cli-tools#pulsar-client"><code>pulsar-client</code></a> tool to listen for messages on the output topic:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-client consume persistent://public/default/exclamation-output \
--subscription-name my-subscription \
--num-messages 0
</code></pre>
<blockquote>
<p>Setting the <code>--num-messages</code> flag to 0 means that the consumer will listen on the topic indefinitely (rather than only accepting a certain number of messages).</p>
</blockquote>
<p>With a listener up and running, we can open up another shell and produce a message on the input topic that we specified:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-client produce persistent://public/default/exclamation-input \
--num-produce 1 \
--messages <span class="hljs-string">"Hello world"</span>
</code></pre>
<p>In the output, you should see the following:</p>
<pre><code class="hljs">--<span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-literal">-</span> <span class="hljs-comment">got</span> <span class="hljs-comment">message</span> --<span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-literal">-</span>
<span class="hljs-comment">Hello</span> <span class="hljs-comment">world!</span>
</code></pre>
<p>Success! As you can see, the message has been successfully processed by the exclamation function. To shut down the function, simply hit <strong>Ctrl+C</strong>.</p>
<p>Here's what happened:</p>
<ul>
<li>The <code>Hello world</code> message that we published to the input topic (<code>persistent://public/default/exclamation-input</code>) was passed to the exclamation function that we ran on our machine</li>
<li>The exclamation function processed the message (providing a result of <code>Hello world!</code>) and published the result to the output topic (<code>persistent://public/default/exclamation-output</code>).</li>
<li>If our exclamation function <em>hadn't</em> been running, Pulsar would have durably stored the message data published to the input topic in <a href="https://bookkeeper.apache.org">Apache BookKeeper</a> until a consumer consumed and acknowledged the message</li>
</ul>
<h2><a class="anchor" aria-hidden="true" id="run-a-pulsar-function-in-cluster-mode"></a><a href="#run-a-pulsar-function-in-cluster-mode" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Run a Pulsar Function in cluster mode</h2>
<p><a href="#run-a-pulsar-function-in-local-run-mode">Local run mode</a> is useful for development and experimentation, but if you want to use Pulsar Functions in a real Pulsar deployment, you'll want to run them in <strong>cluster mode</strong>. In this mode, Pulsar Functions run <em>inside</em> your Pulsar cluster and are managed using the same <a href="/docs/en/2.3.1/reference-pulsar-admin#functions"><code>pulsar-admin functions</code></a> interface that we've been using thus far.</p>
<p>This command, for example, would deploy the same exclamation function we ran locally above <em>in our Pulsar cluster</em> (rather than outside it):</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> create \
--jar examples/api-examples.jar \
--classname org.apache.pulsar.functions.api.examples.ExclamationFunction \
--inputs persistent://public/default/exclamation-input \
--output persistent://public/default/exclamation-output \
--name exclamation
</code></pre>
<p>You should see <code>Created successfully</code> in the output. Now, let's see a list of functions running in our cluster:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> list \
--tenant public \
--namespace default
</code></pre>
<p>We should see just the <code>exclamation</code> function listed there. We can also check the status of our deployed function using the <code>getstatus</code> command:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> getstatus \
--tenant public \
--namespace default \
--name exclamation
</code></pre>
<p>You should see this JSON output:</p>
<pre><code class="hljs css language-json">{
<span class="hljs-attr">"functionStatusList"</span>: [
{
<span class="hljs-attr">"running"</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">"instanceId"</span>: <span class="hljs-string">"0"</span>
}
]
}
</code></pre>
<p>As we can see, (a) the instance is currently running and (b) there is one instance, with an ID of 0, running. We can get other information about the function (topics, tenant, namespace, etc.) using the <code>get</code> command instead of <code>getstatus</code>:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> get \
--tenant public \
--namespace default \
--name exclamation
</code></pre>
<p>You should see this JSON output:</p>
<pre><code class="hljs css language-json">{
<span class="hljs-attr">"tenant"</span>: <span class="hljs-string">"public"</span>,
<span class="hljs-attr">"namespace"</span>: <span class="hljs-string">"default"</span>,
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"exclamation"</span>,
<span class="hljs-attr">"className"</span>: <span class="hljs-string">"org.apache.pulsar.functions.api.examples.ExclamationFunction"</span>,
<span class="hljs-attr">"output"</span>: <span class="hljs-string">"persistent://public/default/exclamation-output"</span>,
<span class="hljs-attr">"autoAck"</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">"inputs"</span>: [
<span class="hljs-string">"persistent://public/default/exclamation-input"</span>
],
<span class="hljs-attr">"parallelism"</span>: <span class="hljs-number">1</span>
}
</code></pre>
<p>As we can see, the parallelism of the function is 1, meaning that only one instance of the function is running in our cluster. Let's update our function to a parallelism of 3 using the <code>update</code> command:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> update \
--jar examples/api-examples.jar \
--classname org.apache.pulsar.functions.api.examples.ExclamationFunction \
--inputs persistent://public/default/exclamation-input \
--output persistent://public/default/exclamation-output \
--tenant public \
--namespace default \
--name exclamation \
--parallelism 3
</code></pre>
<p>You should see <code>Updated successfully</code> in the output. If you run the <code>get</code> command from above for the function, you can see that the parallelism has increased to 3, meaning that there are now three instances of the function running in our cluster:</p>
<pre><code class="hljs css language-json">{
<span class="hljs-attr">"tenant"</span>: <span class="hljs-string">"public"</span>,
<span class="hljs-attr">"namespace"</span>: <span class="hljs-string">"default"</span>,
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"exclamation"</span>,
<span class="hljs-attr">"className"</span>: <span class="hljs-string">"org.apache.pulsar.functions.api.examples.ExclamationFunction"</span>,
<span class="hljs-attr">"output"</span>: <span class="hljs-string">"persistent://public/default/exclamation-output"</span>,
<span class="hljs-attr">"autoAck"</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">"inputs"</span>: [
<span class="hljs-string">"persistent://public/default/exclamation-input"</span>
],
<span class="hljs-attr">"parallelism"</span>: <span class="hljs-number">3</span>
}
</code></pre>
<p>Finally, we can shut down our running function using the <code>delete</code> command:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> delete \
--tenant public \
--namespace default \
--name exclamation
</code></pre>
<p>If you see <code>Deleted successfully</code> in the output, then you've successfully run, updated, and shut down a Pulsar Function running in cluster mode. Congrats! Now, let's go even further and run a brand new function in the next section.</p>
<h2><a class="anchor" aria-hidden="true" id="writing-and-running-a-new-function"></a><a href="#writing-and-running-a-new-function" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Writing and running a new function</h2>
<blockquote>
<p>In order to write and run the <a href="/docs/en/2.3.1/functions-api#functions-for-python">Python</a> function below, you'll need to install a few dependencies:</p>
<pre><code class="hljs css language-bash">$ pip install pulsar-client
</code></pre>
</blockquote>
<p>In the above examples, we ran and managed a pre-written Pulsar Function and saw how it worked. To really get our hands dirty, let's write and our own function from scratch, using the Python API. This simple function will also take a string as input but it will reverse the string and publish the resulting, reversed string to the specified topic.</p>
<p>First, create a new Python file:</p>
<pre><code class="hljs css language-bash">$ touch reverse.py
</code></pre>
<p>In that file, add the following:</p>
<pre><code class="hljs css language-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process</span><span class="hljs-params">(input)</span>:</span>
<span class="hljs-keyword">return</span> input[::<span class="hljs-number">-1</span>]
</code></pre>
<p>Here, the <code>process</code> method defines the processing logic of the Pulsar Function. It simply uses some Python slice magic to reverse each incoming string. Now, we can deploy the function using <code>create</code>:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> create \
--py reverse.py \
--classname reverse \
--inputs persistent://public/default/backwards \
--output persistent://public/default/forwards \
--tenant public \
--namespace default \
--name reverse
</code></pre>
<p>If you see <code>Created successfully</code>, the function is ready to accept incoming messages. Because the function is running in cluster mode, we can <strong>trigger</strong> the function using the <a href="/docs/en/2.3.1/reference-pulsar-admin#trigger"><code>trigger</code></a> command. This command will send a message that we specify to the function and also give us the function's output. Here's an example:</p>
<pre><code class="hljs css language-bash">$ bin/pulsar-admin <span class="hljs-built_in">functions</span> trigger \
--name reverse \
--tenant public \
--namespace default \
--trigger-value <span class="hljs-string">"sdrawrof won si tub sdrawkcab saw gnirts sihT"</span>
</code></pre>
<p>You should get this output:</p>
<pre><code class="hljs">This <span class="hljs-built_in">string</span> was backwards <span class="hljs-keyword">but</span> <span class="hljs-keyword">is</span> now forwards
</code></pre>
<p>Once again, success! We created a brand new Pulsar Function, deployed it in our Pulsar standalone cluster in <a href="#run-a-pulsar-function-in-cluster-mode">cluster mode</a> and successfully triggered the function. If you're ready for more, check out one of these docs:</p>
<h2><a class="anchor" aria-hidden="true" id="packaging-python-dependencies"></a><a href="#packaging-python-dependencies" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Packaging python dependencies</h2>
<p>For python functions requiring dependencies to be deployable in pulsar worker instances in an offline manner, we need to package the artifacts as below.</p>
<h4><a class="anchor" aria-hidden="true" id="client-requirements"></a><a href="#client-requirements" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Client Requirements</h4>
<p>Following programs are required to be installed on the client machine</p>
<pre><code class="hljs">pip \\ <span class="hljs-keyword">required</span> <span class="hljs-keyword">for</span> getting python dependencies
<span class="hljs-built_in">zip</span> \\ <span class="hljs-keyword">for</span> building <span class="hljs-built_in">zip</span> archives
</code></pre>
<h4><a class="anchor" aria-hidden="true" id="python-dependencies"></a><a href="#python-dependencies" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Python Dependencies</h4>
<p>A file named <strong>requirements.txt</strong> is needed with required dependencies for the python function</p>
<pre><code class="hljs">sh==<span class="hljs-number">1.12</span><span class="hljs-number">.14</span>
</code></pre>
<p>Prepare the pulsar function in folder called <strong>src</strong>.</p>
<p>Run the following command to gather the python dependencies in the folder caller <strong>deps</strong></p>
<pre><code class="hljs">pip download \
-<span class="ruby">-only-binary <span class="hljs-symbol">:all</span>: \
</span>-<span class="ruby">-platform manylinux1_x86_64 \
</span>-<span class="ruby">-python-version <span class="hljs-number">27</span> \
</span>-<span class="ruby">-implementation cp \
</span>-<span class="ruby">-abi cp27m -r requirements.txt -d deps
</span>
</code></pre>
<p>Sample output</p>
<pre><code class="hljs">Collecting sh==<span class="hljs-number">1.12</span><span class="hljs-number">.14</span> (<span class="hljs-built_in">from</span> -r requirements.txt (<span class="hljs-built_in">line</span> <span class="hljs-number">1</span>))
Using cached <span class="hljs-keyword">https</span>://<span class="hljs-built_in">files</span>.pythonhosted.org/packages/<span class="hljs-number">4</span><span class="hljs-keyword">a</span>/<span class="hljs-number">22</span>/<span class="hljs-number">17</span>b22ef5b049f12080f5815c41bf94de3c229217609e469001a8f80c1b3d/sh<span class="hljs-number">-1.12</span><span class="hljs-number">.14</span>-py2.py3-<span class="hljs-literal">none</span>-<span class="hljs-keyword">any</span>.whl
Saved ./deps/sh<span class="hljs-number">-1.12</span><span class="hljs-number">.14</span>-py2.py3-<span class="hljs-literal">none</span>-<span class="hljs-keyword">any</span>.whl
Successfully downloaded sh
</code></pre>
<p><strong>Note</strong> pulsar-client is not needed as a dependency as it already installed in the worker node.</p>
<h4><a class="anchor" aria-hidden="true" id="packaging"></a><a href="#packaging" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Packaging</h4>
<p>Create a destination folder with the desired pacaking name eg : <strong>exclamation</strong>, copy <strong>src</strong> and <strong>deps</strong> folder into it and finally compress the folder into a zip archive.</p>
<p>Sample sequence</p>
<pre><code class="hljs">cp -R deps exclamation/
cp -R src exclamation/
ls -la exclamation/
total <span class="hljs-number">7</span>
drwxr-xr-x <span class="hljs-number">5</span> a.ahmed staff <span class="hljs-number">160</span> Nov <span class="hljs-number">6</span> <span class="hljs-number">17</span>:<span class="hljs-number">51</span> .
drwxr-xr-x <span class="hljs-number">12</span> a.ahmed staff <span class="hljs-number">384</span> Nov <span class="hljs-number">6</span> <span class="hljs-number">17</span>:<span class="hljs-number">52</span> ..
drwxr-xr-x <span class="hljs-number">3</span> a.ahmed staff <span class="hljs-number">96</span> Nov <span class="hljs-number">6</span> <span class="hljs-number">17</span>:<span class="hljs-number">51</span> deps
drwxr-xr-x <span class="hljs-number">3</span> a.ahmed staff <span class="hljs-number">96</span> Nov <span class="hljs-number">6</span> <span class="hljs-number">17</span>:<span class="hljs-number">51</span> src
zip -r exclamation.zip exclamation
</code></pre>
<p>Archive <strong>exclamation.zip</strong> can we deployed as function into a pulsar worker, the worker does not need internet connectivity to download packages as they are all included in the zip file.</p>
<ul>
<li><a href="/docs/en/2.3.1/functions-api">The Pulsar Functions API</a></li>
<li><a href="/docs/en/2.3.1/functions-deploying">Deploying Pulsar Functions</a></li>
</ul>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/en/2.3.1/functions-overview"><span class="arrow-prev"></span><span>Overview</span></a><a class="docs-next button" href="/docs/en/2.3.1/functions-api"><span>functions-api</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#prerequisites">Prerequisites</a></li><li><a href="#run-a-standalone-pulsar-cluster">Run a standalone Pulsar cluster</a></li><li><a href="#run-a-pulsar-function-in-local-run-mode">Run a Pulsar Function in local run mode</a></li><li><a href="#run-a-pulsar-function-in-cluster-mode">Run a Pulsar Function in cluster mode</a></li><li><a href="#writing-and-running-a-new-function">Writing and running a new function</a></li><li><a href="#packaging-python-dependencies">Packaging python dependencies</a></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="copyright">Copyright © 2022 The Apache Software Foundation. All Rights Reserved. Apache, Apache Pulsar and the Apache feather logo are trademarks of The Apache Software Foundation.</section><span><script>
const community = document.querySelector("a[href='#community']").parentNode;
const communityMenu =
'<li>' +
'<a id="community-menu" href="#">Community <span style="font-size: 0.75em">&nbsp;▼</span></a>' +
'<div id="community-dropdown" class="hide">' +
'<ul id="community-dropdown-items">' +
'<li><a href="/en/contact">Contact</a></li>' +
'<li><a href="/en/contributing">Contributing</a></li>' +
'<li><a href="/en/coding-guide">Coding guide</a></li>' +
'<li><a href="/en/events">Events</a></li>' +
'<li><a href="https://twitter.com/Apache_Pulsar" target="_blank">Twitter &#x2750</a></li>' +
'<li><a href="https://github.com/apache/pulsar/wiki" target="_blank">Wiki &#x2750</a></li>' +
'<li><a href="https://github.com/apache/pulsar/issues" target="_blank">Issue tracking &#x2750</a></li>' +
'<li><a href="https://pulsar-summit.org/" target="_blank">Pulsar Summit &#x2750</a></li>' +
'<li>&nbsp;</li>' +
'<li><a href="/en/resources">Resources</a></li>' +
'<li><a href="/en/team">Team</a></li>' +
'<li><a href="/en/powered-by">Powered By</a></li>' +
'</ul>' +
'</div>' +
'</li>';
community.innerHTML = communityMenu;
const communityMenuItem = document.getElementById("community-menu");
const communityDropDown = document.getElementById("community-dropdown");
communityMenuItem.addEventListener("click", function(event) {
event.preventDefault();
if (communityDropDown.className == 'hide') {
communityDropDown.className = 'visible';
} else {
communityDropDown.className = 'hide';
}
});
</script></span></footer></div><script>window.twttr=(function(d,s, id){var js,fjs=d.getElementsByTagName(s)[0],t=window.twttr||{};if(d.getElementById(id))return t;js=d.createElement(s);js.id=id;js.src='https://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js, fjs);t._e = [];t.ready = function(f) {t._e.push(f);};return t;}(document, 'script', 'twitter-wjs'));</script></body></html>