blob: 8ed6ccbfc6747161f83e40bfbfadaeb89c79c3e6 [file] [log] [blame]
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>How transactions work? · Apache Pulsar</title><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="generator" content="Docusaurus"/><meta name="description" content="This section describes transaction components and how the components work together. For the complete design details, see [PIP-31: Transactional Streaming](https://docs.google.com/document/d/145VYp09JKTw9jAT-7yNyFU255FptB2_B2Fye100ZXDI/edit#heading=h.bm5ainqxosrx)."/><meta name="docsearch:version" content="next"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="How transactions work? · Apache Pulsar"/><meta property="og:type" content="website"/><meta property="og:url" content="https://pulsar.apache.org/"/><meta property="og:description" content="This section describes transaction components and how the components work together. For the complete design details, see [PIP-31: Transactional Streaming](https://docs.google.com/document/d/145VYp09JKTw9jAT-7yNyFU255FptB2_B2Fye100ZXDI/edit#heading=h.bm5ainqxosrx)."/><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>next</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/en/next/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/next/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/next/txn-how">日本語</a></li><li><a href="/docs/fr/next/txn-how">Français</a></li><li><a href="/docs/ko/next/txn-how">한국어</a></li><li><a href="/docs/zh-CN/next/txn-how">中文</a></li><li><a href="/docs/zh-TW/next/txn-how">繁體中文</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>Transactions</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Get Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/getting-started-standalone">Run Pulsar locally</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/getting-started-docker">Run Pulsar in Docker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/getting-started-helm">Run Pulsar in Kubernetes</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/next/concepts-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-messaging">Messaging</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-architecture-overview">Architecture</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-clients">Clients</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-replication">Geo Replication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-multi-tenancy">Multi Tenancy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-authentication">Authentication and Authorization</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-topic-compaction">Topic Compaction</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-proxy-sni-routing">Proxy support with SNI routing</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/concepts-multiple-advertised-listeners">Multiple advertised listeners</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar Schema</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/schema-get-started">Get started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/schema-understand">Understand schema</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/schema-evolution-compatibility">Schema evolution and compatibility</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/schema-manage">Manage schema</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar Functions</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-runtime">Setup: Configure Functions runtime</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-worker">Setup: Pulsar Functions Worker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-develop">How-to: Develop</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-package">How-to: Package</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-debug">How-to: Debug</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-deploy">How-to: Deploy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/functions-cli">Reference: CLI</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/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/next/io-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-quickstart">Get started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-use">Use</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-debug">Debug</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-connectors">Built-in connector</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-cdc">CDC connector</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-develop">Develop</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/io-cli">CLI</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar SQL</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/sql-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/sql-getting-started">Query data</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/sql-deployment-configurations">Configuration and deployment</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/sql-rest-api">REST APIs</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Tiered Storage</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/tiered-storage-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/tiered-storage-aws">AWS S3 offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/tiered-storage-gcs">GCS offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/tiered-storage-filesystem">Filesystem offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/tiered-storage-azure">Azure BlobStore offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/tiered-storage-aliyun">Aliyun OSS offloader</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Transactions</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/txn-why">Why transactions?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/txn-what">What are transactions?</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/en/next/txn-how">How transactions work?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/txn-use">How to use transactions?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/txn-monitor">How to monitor transactions?</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Kubernetes (Helm)</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/helm-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/helm-prepare">Prepare</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/helm-install">Install</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/helm-deploy">Deployment</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/helm-upgrade">Upgrade</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/helm-tools">Required Tools</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Deployment</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/deploy-aws">Amazon Web Services</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/deploy-kubernetes">Kubernetes</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/deploy-bare-metal">Bare metal</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/deploy-bare-metal-multi-cluster">Bare metal multi-cluster</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/deploy-docker">Docker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/deploy-monitoring">Monitor</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Administration</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-zk-bk">ZooKeeper and BookKeeper</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-geo">Geo-replication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-pulsar-manager">Pulsar Manager</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-stats">Pulsar statistics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-load-balance">Load balance</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-proxy">Pulsar proxy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-upgrade">Upgrade</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/administration-isolation">Pulsar isolation</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Security</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/security-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-policy-and-supported-versions">Security Policy and Supported Versions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-tls-transport">Transport Encryption using TLS</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-tls-authentication">Authentication using TLS</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-tls-keystore">Using TLS with KeyStore configure</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-jwt">Authentication using JWT</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-athenz">Authentication using Athenz</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-kerberos">Authentication using Kerberos</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-oauth2">Authentication using OAuth 2.0 access tokens</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-authorization">Authorization and ACLs</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-encryption">End-to-End Encryption</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-extending">Extend Authentication and Authorization</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/security-bouncy-castle">Bouncy Castle Providers</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Performance</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/performance-pulsar-perf">Pulsar Perf</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Client Libraries</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-java">Java</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-go">Go</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-python">Python</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-cpp">C++</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-node">Node.js</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-websocket">WebSocket</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-dotnet">C#</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/client-libraries-rest">REST</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Admin API</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-clusters">Clusters</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-tenants">Tenants</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-brokers">Brokers</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-namespaces">Namespaces</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-permissions">Permissions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-topics">Topics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-functions">Functions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/admin-api-packages">Packages</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Adaptors</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/adaptors-kafka">Kafka client wrapper</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/adaptors-spark">Apache Spark</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/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/next/cookbooks-compaction">Topic compaction</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/cookbooks-deduplication">Message deduplication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/cookbooks-non-persistent">Non-persistent messaging</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/cookbooks-retention-expiry">Message retention and expiry</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/cookbooks-encryption">Encryption</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/cookbooks-message-queue">Message queue</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/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/next/develop-tools">Simulation tools</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/developing-binary-protocol">Binary protocol</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/develop-load-manager">Modular load manager</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/develop-plugin">Plugin</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Reference</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/next/reference-terminology">Terminology</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/reference-cli-tools">Pulsar CLI tools</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/reference-configuration">Pulsar configuration</a></li><li class="navListItem"><a class="navItem" href="/docs/en/next/reference-metrics">Pulsar Metrics</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/txn-how.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">How transactions work?</h1></header><article><div><span><p>This section describes transaction components and how the components work together. For the complete design details, see <a href="https://docs.google.com/document/d/145VYp09JKTw9jAT-7yNyFU255FptB2_B2Fye100ZXDI/edit#heading=h.bm5ainqxosrx">PIP-31: Transactional Streaming</a>.</p>
<h2><a class="anchor" aria-hidden="true" id="key-concept"></a><a href="#key-concept" 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>Key concept</h2>
<p>It is important to know the following key concepts, which is a prerequisite for understanding how transactions work.</p>
<h3><a class="anchor" aria-hidden="true" id="transaction-coordinator"></a><a href="#transaction-coordinator" 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>Transaction coordinator</h3>
<p>The transaction coordinator (TC) is a module running inside a Pulsar broker.</p>
<ul>
<li><p>It maintains the entire life cycle of transactions and prevents a transaction from getting into an incorrect status.</p></li>
<li><p>It handles transaction timeout, and ensures that the transaction is aborted after a transaction timeout.</p></li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="transaction-log"></a><a href="#transaction-log" 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>Transaction log</h3>
<p>All the transaction metadata persists in the transaction log. The transaction log is backed by a Pulsar topic. If the transaction coordinator crashes, it can restore the transaction metadata from the transaction log.</p>
<p>The transaction log stores the transaction status rather than actual messages in the transaction (the actual messages are stored in the actual topic partitions).</p>
<h3><a class="anchor" aria-hidden="true" id="transaction-buffer"></a><a href="#transaction-buffer" 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>Transaction buffer</h3>
<p>Messages produced to a topic partition within a transaction are stored in the transaction buffer (TB) of that topic partition. The messages in the transaction buffer are not visible to consumers until the transactions are committed. The messages in the transaction buffer are discarded when the transactions are aborted.</p>
<p>Transaction buffer stores all ongoing and aborted transactions in memory. All messages are sent to the actual partitioned Pulsar topics. After transactions are committed, the messages in the transaction buffer are materialized (visible) to consumers. When the transactions are aborted, the messages in the transaction buffer are discarded.</p>
<h3><a class="anchor" aria-hidden="true" id="transaction-id"></a><a href="#transaction-id" 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>Transaction ID</h3>
<p>Transaction ID (TxnID) identifies a unique transaction in Pulsar. The transaction ID is 128-bit. The highest 16 bits are reserved for the ID of the transaction coordinator, and the remaining bits are used for monotonically increasing numbers in each transaction coordinator. It is easy to locate the transaction crash with the TxnID.</p>
<h3><a class="anchor" aria-hidden="true" id="pending-acknowledge-state"></a><a href="#pending-acknowledge-state" 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>Pending acknowledge state</h3>
<p>Pending acknowledge state maintains message acknowledgments within a transaction before a transaction completes. If a message is in the pending acknowledge state, the message cannot be acknowledged by other transactions until the message is removed from the pending acknowledge state.</p>
<p>The pending acknowledge state is persisted to the pending acknowledge log (cursor ledger). A new broker can restore the state from the pending acknowledge log to ensure the acknowledgement is not lost.</p>
<h2><a class="anchor" aria-hidden="true" id="data-flow"></a><a href="#data-flow" 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>Data flow</h2>
<p>At a high level, the data flow can be split into several steps:</p>
<ol>
<li><p>Begin a transaction.</p></li>
<li><p>Publish messages with a transaction.</p></li>
<li><p>Acknowledge messages with a transaction.</p></li>
<li><p>End a transaction.</p></li>
</ol>
<p>To help you debug or tune the transaction for better performance, review the following diagrams and descriptions.</p>
<h3><a class="anchor" aria-hidden="true" id="1-begin-a-transaction"></a><a href="#1-begin-a-transaction" 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>1. Begin a transaction</h3>
<p>Before introducing the transaction in Pulsar, a producer is created and then messages are sent to brokers and stored in data logs.</p>
<p><img src="/docs/assets/txn-3.png" alt=""></p>
<p>Let’s walk through the steps for <em>beginning a transaction</em>.</p>
<table>
<tr>
<td>Step
</td>
<td>Description
</td>
</tr>
<tr>
<td>1.1<br>New Txn
</td>
<td>The first step is that the Pulsar client finds the transaction coordinator.
</td>
</tr>
<tr>
<td>1.2<br>Allocate Txn ID
</td>
<td>The transaction coordinator allocates a transaction ID for the transaction. In the transaction log, the transaction is logged with its transaction ID and status (OPEN), which ensures the transaction status is persisted regardless of transaction coordinator crashes.
</td>
</tr>
<tr>
<td>1.3<br>Send Result
</td>
<td>The transaction log sends the result of persisting the transaction ID to the transaction coordinator.
</td>
</tr>
<tr>
<td>1.4<br>Bring Txn ID
</td>
<td>After the transaction status entry is logged, the transaction coordinator brings the transaction ID back to the Pulsar client.
</td>
</tr>
</table>
<h3><a class="anchor" aria-hidden="true" id="2-publish-messages-with-a-transaction"></a><a href="#2-publish-messages-with-a-transaction" 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>2. Publish messages with a transaction</h3>
<p>In this stage, the Pulsar client enters a transaction loop, repeating the <code>consume-process-produce</code> operation for all the messages that comprise the transaction. This is a long phase and is potentially composed of multiple produce and acknowledgement requests.</p>
<p><img src="/docs/assets/txn-4.png" alt=""></p>
<p>Let’s walk through the steps for <em>publishing messages with a transaction</em>.</p>
<table>
<tr>
<td>Step
</td>
<td>Description
</td>
</tr>
<tr>
<td>2.1.1<br>Add Produced Partitions to Txn
</td>
<td>Before the Pulsar client produces messages to a new topic partition, it sends a request to the transaction coordinator to add the partition to the transaction.
</td>
</tr>
<tr>
<td>2.1.2<br>Log Partition Changes of Txn
</td>
<td>The transaction coordinator logs the partition changes of the transaction into the transaction log for durability, which ensures the transaction coordinator knows all the partitions that a transaction is handling. The transaction coordinator can commit or abort changes on each partition at the end-partition phase.
</td>
</tr>
<tr>
<td>2.1.3<br>Send Result
</td>
<td>The transaction log sends the result of logging the new partition (used for producing messages) to the transaction coordinator.
</td>
</tr>
<tr>
<td>2.1.4<br>Send Result
</td>
<td>The transaction coordinator sends the result of adding a new produced partition to the transaction.
</td>
</tr>
<tr>
<td>2.2.1<br>Produce Msgs to Partitions w/Txn
</td>
<td>The Pulsar client starts producing messages to partitions. The flow of this part is the same as the normal flow of producing messages except that the batch of messages produced by a transaction contains transaction IDs.
</td>
</tr>
<tr>
<td>2.2.2<br>Write Msgs
</td>
<td>The broker writes messages to a partition.
</td>
</tr>
</table>
<h3><a class="anchor" aria-hidden="true" id="3-acknowledge-messages-with-a-transaction"></a><a href="#3-acknowledge-messages-with-a-transaction" 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>3. Acknowledge messages with a transaction</h3>
<p>In this phase, the Pulsar client sends a request to the transaction coordinator and a new subscription is acknowledged as a part of a transaction.</p>
<p><img src="/docs/assets/txn-5.png" alt=""></p>
<p>Let’s walk through the steps for <em>acknowledging messages with a transaction</em>.</p>
<table>
<tr>
<td>Step
</td>
<td>Description
</td>
</tr>
<tr>
<td>3.1.1<br>Send Request
</td>
<td>The Pulsar client sends a request to add an acknowledged subscription to the transaction coordinator.
</td>
</tr>
<tr>
<td>3.1.2<br>Log Subscription
</td>
<td>The transaction coordinator logs the addition of subscription, which ensures that it knows all subscriptions handled by a transaction and can commit or abort changes on each subscription at the end phase.
</td>
</tr>
<tr>
<td>3.1.3<br>Send Result
</td>
<td>The transaction log sends the result of logging the new partition (used for acknowledging messages) to the transaction coordinator.
</td>
</tr>
<tr>
<td>3.1.4<br>Send Result
</td>
<td>The transaction coordinator sends the result of adding the new acknowledged partition to the transaction.
</td>
</tr>
<tr>
<td>3.2<br>Ack Msgs w/ Txn
</td>
<td>The Pulsar client acknowledges messages on the subscription. The flow of this part is the same as the normal flow of acknowledging messages except that the acknowledged request carries a transaction ID.
</td>
</tr>
<tr>
<td>3.3<br>Check Ack
</td>
<td>The broker receiving the acknowledgement request checks if the acknowledgment belongs to a transaction or not.<br>If it belongs to a transaction, the broker marks the message as in PENDING_ACK status, which means the message can not be acknowledged or negative-acknowledged by other consumers using the same subscription until the acknowledgement is committed or aborted.<br>If there are two transactions attempting to acknowledge on one message with the same subscription, only one transaction succeeds and the other transaction is conflicted. The Pulsar client aborts the whole transaction when it tries to acknowledge but detects a conflict. The conflict can be detected on both individual acknowledgements and cumulative acknowledgements.
</td>
</tr>
</table>
<h3><a class="anchor" aria-hidden="true" id="4-end-a-transaction"></a><a href="#4-end-a-transaction" 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>4. End a transaction</h3>
<p>At the end of a transaction, the Pulsar client decides to commit or abort the transaction. The transaction can be aborted when a conflict is detected on acknowledging messages.</p>
<h4><a class="anchor" aria-hidden="true" id="41-end-transaction-request"></a><a href="#41-end-transaction-request" 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>4.1 End transaction request</h4>
<p>When the Pulsar client finishes a transaction, it issues an end transaction request.</p>
<p><img src="/docs/assets/txn-6.png" alt=""></p>
<p>Let’s walk through the steps for <em>ending the transaction</em>.</p>
<table>
<tr>
<td>Step
</td>
<td>Description
</td>
</tr>
<tr>
<td>4.1.1<br>End Txn request
</td>
<td>The Pulsar client issues an end transaction request (with a field indicating whether the transaction is to be committed or aborted) to the transaction coordinator.
</td>
</tr>
<tr>
<td>4.1.2<br>Committing Txn
</td>
<td>The transaction coordinator writes a COMMITTING or ABORTING message to its transaction log.
</td>
</tr>
<tr>
<td>4.1.3<br>Send Results
</td>
<td>The transaction log sends the result of logging the committing or aborting status.
</td>
</tr>
</table>
<h4><a class="anchor" aria-hidden="true" id="42-finalize-a-transaction"></a><a href="#42-finalize-a-transaction" 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>4.2 Finalize a transaction</h4>
<p>The transaction coordinator starts the process of committing or aborting messages to all the partitions involved in this transaction.</p>
<p><img src="/docs/assets/txn-7.png" alt=""></p>
<p>Let’s walk through the steps for <em>finalizing a transaction</em>.</p>
<table>
<tr>
<td>Step
</td>
<td>Description
</td>
</tr>
<tr>
<td>4.2.1<br>Commit Txn on Subscriptions
</td>
<td>The transaction coordinator commits transactions on subscriptions and commits transactions on partitions at the same time.
</td>
</tr>
<tr>
<td>4.2.2<br>Write Marker
</td>
<td>The broker (produce) writes produced committed markers to the actual partitions. At the same time, the broker (ack) writes acked committed marks to the subscription pending ack partitions.
</td>
</tr>
<tr>
<td>4.2.3<br>Send Result
</td>
<td>The data log sends the result of writing produced committed marks to the broker. At the same time, pending ack data log sends the result of writing acked committed marks to the broker. The cursor moves to the next position.
<ul>
<li>If the transaction is committed, the PENDING ACK status becomes `ACK` status.
<li>If the transaction is aborted, the PENDING ACK status becomes UNACK status. (Aborting an acknowledgment results in the message being re-delivered to other consumers.)
</li>
</ul>
</td>
</tr>
</table>
<h4><a class="anchor" aria-hidden="true" id="43-mark-a-transaction-as-committed-or-aborted"></a><a href="#43-mark-a-transaction-as-committed-or-aborted" 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>4.3 Mark a transaction as COMMITTED or ABORTED</h4>
<p>The transaction coordinator writes the final transaction status to the transaction log to complete the transaction.</p>
<p><img src="/docs/assets/txn-8.png" alt=""></p>
<p>Let’s walk through the steps for <em>marking a transaction as COMMITTED or ABORTED</em>.</p>
<table>
<tr>
<td>Step
</td>
<td>Description
</td>
</tr>
<tr>
<td>4.3.1<br>Commit Txn
</td>
<td>After all produced messages and acknowledgements to all partitions involved in this transaction have been successfully committed or aborted, the transaction coordinator writes the final COMMITTED or ABORTED transaction status messages to its transaction log, indicating that the transaction is complete. All the messages associated with the transaction in its transaction log can be safely removed.
</td>
</tr>
<tr>
<td>4.3.2<br>Send Result
</td>
<td>The transaction log sends the result of the committed transaction to the transaction coordinator.
</td>
</tr>
<tr>
<td>4.3.3<br>Send Result
</td>
<td>The transaction coordinator sends the result of the committed transaction to the Pulsar client.
</td>
</tr>
</table>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/en/next/txn-what"><span class="arrow-prev"></span><span>What are transactions?</span></a><a class="docs-next button" href="/docs/en/next/txn-use"><span>How to use transactions?</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#key-concept">Key concept</a><ul class="toc-headings"><li><a href="#transaction-coordinator">Transaction coordinator</a></li><li><a href="#transaction-log">Transaction log</a></li><li><a href="#transaction-buffer">Transaction buffer</a></li><li><a href="#transaction-id">Transaction ID</a></li><li><a href="#pending-acknowledge-state">Pending acknowledge state</a></li></ul></li><li><a href="#data-flow">Data flow</a><ul class="toc-headings"><li><a href="#1-begin-a-transaction">1. Begin a transaction</a></li><li><a href="#2-publish-messages-with-a-transaction">2. Publish messages with a transaction</a></li><li><a href="#3-acknowledge-messages-with-a-transaction">3. Acknowledge messages with a transaction</a></li><li><a href="#4-end-a-transaction">4. End a transaction</a></li></ul></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>