blob: dc079f1c05afb0fe629f0a1479f2bd6c15ecd73f [file] [log] [blame]
<!DOCTYPE html>
<html lang="en" dir=ZgotmplZ>
<head>
<link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
<script src="/bootstrap/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" type="text/css" href="/font-awesome/css/font-awesome.min.css">
<script src="/js/anchor.min.js"></script>
<script src="/js/flink.js"></script>
<link rel="canonical" href="https://flink.apache.org/2021/04/15/stateful-functions-3.0.0-remote-functions-front-and-center/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="The Apache Flink community is happy to announce the release of Stateful Functions (StateFun) 3.0.0! Stateful Functions is a cross-platform stack for building Stateful Serverless applications, making it radically simpler to develop scalable, consistent, and elastic distributed applications.
This new release brings remote functions to the front and center of StateFun, making the disaggregated setup that separates the application logic from the StateFun cluster the default. It is now easier, more efficient, and more ergonomic to write applications that live in their own processes or containers.">
<meta name="theme-color" content="#FFFFFF"><meta property="og:title" content="Stateful Functions 3.0.0: Remote Functions Front and Center" />
<meta property="og:description" content="The Apache Flink community is happy to announce the release of Stateful Functions (StateFun) 3.0.0! Stateful Functions is a cross-platform stack for building Stateful Serverless applications, making it radically simpler to develop scalable, consistent, and elastic distributed applications.
This new release brings remote functions to the front and center of StateFun, making the disaggregated setup that separates the application logic from the StateFun cluster the default. It is now easier, more efficient, and more ergonomic to write applications that live in their own processes or containers." />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://flink.apache.org/2021/04/15/stateful-functions-3.0.0-remote-functions-front-and-center/" /><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2021-04-15T08:00:00+00:00" />
<meta property="article:modified_time" content="2021-04-15T08:00:00+00:00" />
<title>Stateful Functions 3.0.0: Remote Functions Front and Center | Apache Flink</title>
<link rel="manifest" href="/manifest.json">
<link rel="icon" href="/favicon.png" type="image/x-icon">
<link rel="stylesheet" href="/book.min.22eceb4d17baa9cdc0f57345edd6f215a40474022dfee39b63befb5fb3c596b5.css" integrity="sha256-IuzrTRe6qc3A9XNF7dbyFaQEdAIt/uObY777X7PFlrU=">
<script defer src="/en.search.min.2698f0d1b683dae4d6cb071668b310a55ebcf1c48d11410a015a51d90105b53e.js" integrity="sha256-Jpjw0baD2uTWywcWaLMQpV688cSNEUEKAVpR2QEFtT4="></script>
<!--
Made with Book Theme
https://github.com/alex-shpak/hugo-book
-->
<meta name="generator" content="Hugo 0.124.1">
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['disableCookies']);
_paq.push(["setDomains", ["*.flink.apache.org","*.nightlies.apache.org/flink"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body dir=ZgotmplZ>
<header>
<nav class="navbar navbar-expand-xl">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<img src="/img/logo/png/100/flink_squirrel_100_color.png" alt="Apache Flink" height="47" width="47" class="d-inline-block align-text-middle">
<span>Apache Flink</span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<i class="fa fa-bars navbar-toggler-icon"></i>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">About</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="/what-is-flink/flink-architecture/">Architecture</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/flink-applications/">Applications</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/flink-operations/">Operations</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/use-cases/">Use Cases</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/powered-by/">Powered By</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/roadmap/">Roadmap</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/community/">Community & Project Info</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/security/">Security</a>
</li>
<li>
<a class="dropdown-item" href="/what-is-flink/special-thanks/">Special Thanks</a>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">Getting Started</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-docs-stable/docs/try-flink/local_installation/">With Flink<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-stable/docs/try-flink-kubernetes-operator/quick-start/">With Flink Kubernetes Operator<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-cdc-docs-stable/docs/get-started/introduction/">With Flink CDC<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-ml-docs-stable/docs/try-flink-ml/quick-start/">With Flink ML<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-statefun-docs-stable/getting-started/project-setup.html">With Flink Stateful Functions<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-docs-stable/docs/learn-flink/overview/">Training Course<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">Documentation</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-docs-stable/">Flink 1.19 (stable)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-docs-master/">Flink Master (snapshot)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-stable/">Kubernetes Operator 1.8 (latest)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-main">Kubernetes Operator Main (snapshot)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-cdc-docs-stable">CDC 3.0 (stable)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-cdc-docs-master">CDC Master (snapshot)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-ml-docs-stable/">ML 2.3 (stable)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-ml-docs-master">ML Master (snapshot)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-statefun-docs-stable/">Stateful Functions 3.3 (stable)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="dropdown-item" href="https://nightlies.apache.org/flink/flink-statefun-docs-master">Stateful Functions Master (snapshot)<i class="link fa fa-external-link title" aria-hidden="true"></i>
</a>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">How to Contribute</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="/how-to-contribute/overview/">Overview</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/contribute-code/">Contribute Code</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/reviewing-prs/">Review Pull Requests</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/code-style-and-quality-preamble/">Code Style and Quality Guide</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/contribute-documentation/">Contribute Documentation</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/documentation-style-guide/">Documentation Style Guide</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/improve-website/">Contribute to the Website</a>
</li>
<li>
<a class="dropdown-item" href="/how-to-contribute/getting-help/">Getting Help</a>
</li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="/posts/">Flink Blog</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/downloads/">Downloads</a>
</li>
</ul>
<div class="book-search">
<div class="book-search-spinner hidden">
<i class="fa fa-refresh fa-spin"></i>
</div>
<form class="search-bar d-flex" onsubmit="return false;"su>
<input type="text" id="book-search-input" placeholder="Search" aria-label="Search" maxlength="64" data-hotkeys="s/">
<i class="fa fa-search search"></i>
<i class="fa fa-circle-o-notch fa-spin spinner"></i>
</form>
<div class="book-search-spinner hidden"></div>
<ul id="book-search-results"></ul>
</div>
</div>
</div>
</nav>
<div class="navbar-clearfix"></div>
</header>
<main class="flex">
<section class="container book-page">
<article class="markdown">
<h1>
<a href="/2021/04/15/stateful-functions-3.0.0-remote-functions-front-and-center/">Stateful Functions 3.0.0: Remote Functions Front and Center</a>
</h1>
April 15, 2021 -
Igal Shilman
<a href="https://twitter.com/IgalShilman">(@IgalShilman)</a>
Tzu-Li (Gordon) Tai
<a href="https://twitter.com/tzulitai">(@tzulitai)</a>
<p><p>The Apache Flink community is happy to announce the release of Stateful Functions (StateFun) 3.0.0!
Stateful Functions is a cross-platform stack for building Stateful Serverless applications, making it radically simpler
to develop scalable, consistent, and elastic distributed applications.</p>
<p>This new release brings <strong>remote functions to the front and center of StateFun</strong>, making the disaggregated setup that
separates the application logic from the StateFun cluster the default. It is now easier, more efficient, and more
ergonomic to write applications that live in their own processes or containers. With the new Java SDK this is now also
possible for all JVM languages, in addition to Python.</p>
<h2 id="background">
Background
<a class="anchor" href="#background">#</a>
</h2>
<p>Starting with the first StateFun release, before the project was donated to the Apache Software Foundation, our focus was: <strong>making scalable stateful applications easy to build and run</strong>.</p>
<p>The first StateFun version introduced an SDK that allowed writing stateful functions that build up a StateFun application packaged and deployed as a particular Flink job submitted to a Flink cluster. Having functions executing within the same JVM as Flink has some advantages, such as the deployment&rsquo;s performance and immutability. However, it had a few limitations:</p>
<ol>
<li>❌ ⠀Functions can be written only in a JVM based language.</li>
<li>❌ ⠀A blocking call/CPU heavy task in one function can affect other functions and operations that need to complete in a timely manner, such as checkpointing.</li>
<li>❌ ⠀Deploying a new version of the function required a stateful upgrade of the backing Flink job.</li>
</ol>
<p>With StateFun 2.0.0, the debut official release after the project was donated to Apache Flink, the community introduced the concept of <em>remote functions</em>, together with an additional SDK for the Python language.
A remote function is a function that executes in a separate process and is invoked via HTTP by the StateFun cluster processes.
Remote functions introduce a new and exciting capability: <strong>state and compute disaggregation</strong> - allowing users to scale the functions independently of the StateFun cluster, which essentially plays the role of handling messaging and state in a consistent and fault-tolerant manner.</p>
<p>While remote functions did address the limitations (1) and (2) mentioned above, we still had some room to improve:</p>
<ol>
<li>❌ ⠀A stateful restart of the StateFun processes is required to register a new function or to change the state definitions of an existing function.</li>
<li>❌ ⠀The SDK had a few friction points around state and messaging ergonomics - it had a heavy dependency on Google’s Protocol Buffers for it’s multi-language object representation.</li>
</ol>
<p>As business requirements evolve, the application logic naturally evolves with it. For StateFun applications, this often means
typical changes such as adding new functions to the application or updating some existing functions to include new state to be persisted.
This is where the first limitation becomes an issue - such operations require a stateful restart of the StateFun cluster
in order for the changes to be discovered, meaning that <em>all</em> functions of the application would have some downtime for
this to take effect. With remote functions being standalone instances that are supposedly independent of the StateFun cluster processes,
this is obviously non-ideal. By making remote functions the default in StateFun, we&rsquo;re aiming at enabling full flexibility
and ease of operations for application upgrades.</p>
<p>The second limitation around state and messaging ergonomics had came up a few times from our users. Prior to this release,
all state values and message objects were strictly required to be Protobuf objects. This made it cumbersome to use common
types such as JSON or simple strings as state and messages.</p>
<p>With the new StateFun 3.0.0 release, the community has enhanced the remote functions protocol (the protocol that describes how StateFun communicates with the remote function processes) to address all the issues mentioned above.
Building on the new protocol, we rewrote the Python SDK and introduced a brand new remote Java SDK.</p>
<h2 id="new-features">
New Features
<a class="anchor" href="#new-features">#</a>
</h2>
<h3 id="unified-language-sdks">
Unified Language SDKs
<a class="anchor" href="#unified-language-sdks">#</a>
</h3>
<p>One of the goals that we set up to achieve with the SDKs is a unified set of concepts across all the languages.
Having standard and unified SDK concepts across the board makes it straightforward for users to switch the languages their
functions are implemented in.</p>
<p>Here is the same function written with the updated Python SDK and newly added Java SDK in StateFun 3.0.0:</p>
<h4 id="python">
Python
<a class="anchor" href="#python">#</a>
</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@functions.bind</span><span class="p">(</span><span class="n">typename</span><span class="o">=</span><span class="s2">&#34;example/greeter&#34;</span><span class="p">,</span> <span class="n">specs</span><span class="o">=</span><span class="p">[</span><span class="n">ValueSpec</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;visits&#34;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">IntType</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">greeter</span><span class="p">(</span><span class="n">context</span><span class="p">:</span> <span class="n">Context</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># update the visit count.</span>
</span></span><span class="line"><span class="cl"> <span class="n">visits</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">storage</span><span class="o">.</span><span class="n">visits</span> <span class="ow">or</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="n">visits</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"> <span class="n">context</span><span class="o">.</span><span class="n">storage</span><span class="o">.</span><span class="n">visits</span> <span class="o">=</span> <span class="n">visits</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># compute a greeting</span>
</span></span><span class="line"><span class="cl"> <span class="n">name</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">greeting</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;Hello there </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> at the </span><span class="si">{</span><span class="n">visits</span><span class="si">}</span><span class="s2">th time!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">caller</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">caller</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">context</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">message_builder</span><span class="p">(</span><span class="n">target_typename</span><span class="o">=</span><span class="n">caller</span><span class="o">.</span><span class="n">typename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">target_id</span><span class="o">=</span><span class="n">caller</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">str_value</span><span class="o">=</span><span class="n">greeting</span><span class="p">))</span>
</span></span></code></pre></div><h4 id="java">
Java
<a class="anchor" href="#java">#</a>
</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Greeter</span><span class="w"> </span><span class="kd">implements</span><span class="w"> </span><span class="n">StatefulFunction</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">ValueSpec</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span><span class="w"> </span><span class="n">VISITS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ValueSpec</span><span class="p">.</span><span class="na">named</span><span class="p">(</span><span class="s">&#34;visits&#34;</span><span class="p">).</span><span class="na">withIntType</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@Override</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span><span class="w"> </span><span class="nf">apply</span><span class="p">(</span><span class="n">Context</span><span class="w"> </span><span class="n">context</span><span class="p">,</span><span class="w"> </span><span class="n">Message</span><span class="w"> </span><span class="n">message</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// update the visits count</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">visits</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">context</span><span class="p">.</span><span class="na">storage</span><span class="p">().</span><span class="na">get</span><span class="p">(</span><span class="n">VISITS</span><span class="p">).</span><span class="na">orElse</span><span class="p">(</span><span class="n">0</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">visits</span><span class="o">++</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">context</span><span class="p">.</span><span class="na">storage</span><span class="p">().</span><span class="na">set</span><span class="p">(</span><span class="n">VISITS</span><span class="p">,</span><span class="w"> </span><span class="n">visits</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// compute a greeting</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">message</span><span class="p">.</span><span class="na">asUtf8String</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="p">.</span><span class="na">format</span><span class="p">(</span><span class="s">&#34;Hello there %s at the %d-th time!\n&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">visits</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// reply to the caller with a greeting</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">caller</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">context</span><span class="p">.</span><span class="na">caller</span><span class="p">().</span><span class="na">get</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">context</span><span class="p">.</span><span class="na">send</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">MessageBuilder</span><span class="p">.</span><span class="na">forAddress</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">withValue</span><span class="p">(</span><span class="n">greeting</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">context</span><span class="p">.</span><span class="na">done</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Although there are some language specific differences, the terms and concepts are the same:</p>
<ul>
<li>an address scoped storage acting as a key-value store for a particular address.</li>
<li>a unified cross-language way to send, receive, and store values across languages (see also <em>Cross-Language Type System</em> below).</li>
<li><code>ValueSpec</code> to describe the state name, type and possibly expiration configuration. Please note that it is no longer necessary to declare the state ahead of time in a <code>module.yaml</code>.</li>
</ul>
<p>For a detailed SDK tutorial, we would like to encourage you to visit:</p>
<ul>
<li><a href="https://github.com/apache/flink-statefun-playground/tree/release-3.0/java/showcase">Java SDK showcase</a></li>
<li><a href="https://github.com/apache/flink-statefun-playground/tree/release-3.0/python/showcase">Python SDK showcase</a></li>
</ul>
<h3 id="cross-language-type-system">
Cross-Language Type System
<a class="anchor" href="#cross-language-type-system">#</a>
</h3>
<p>StateFun 3.0.0 introduces a new type system with cross-language support for common primitive types, such as boolean,
integer, long, etc. This is of course all transparent for the user, so you don&rsquo;t need to worry about it. Functions
implemented in various languages (e.g. Java or Python) can message each other by directly sending supported primitive
values as message arguments. Moreover, the type system is used for state values as well - so, you can expect that a function
can safely read previous state after reimplementing it in a different language.</p>
<p>The type system is also very easily extensible to support custom message types, such as JSON or Protobuf messages.
StateFun makes this super easy by providing builder utilities to help you create custom types.</p>
<h3 id="dynamic-registration-of-state-and-functions">
Dynamic Registration of State and Functions
<a class="anchor" href="#dynamic-registration-of-state-and-functions">#</a>
</h3>
<p>Starting with this release it is now possible to dynamically register new functions without going through a stateful upgrade cycle of the StateFun cluster (which entails the standard process of performing a stateful restart of a Flink job).
This is achieved with a new <code>endpoint</code> definition that supports target URL templating.</p>
<p>Consider the following definition:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">endpoints</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">endpoint</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">meta</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">http</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">functions</span><span class="p">:</span><span class="w"> </span><span class="l">example/*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">urlPathTemplate</span><span class="p">:</span><span class="w"> </span><span class="l">https://loadbalancer.svc.cluster.local/{function.name} </span><span class="w">
</span></span></span></code></pre></div><p>With this definition, all messages being addressed to functions under the namespace <code>example</code> will be forwarded to the specified templated URL.
For example, a message being addressed to a function of typename <code>example/greeter</code> would be forwarded to <code>https://loadbalancer.svc.cluster.local/greeter</code>.</p>
<p>This unlocks the possibility to dynamically introduce new functions into the topology without ever restarting the Stateful Functions application.</p>
<h2 id="summary">
Summary
<a class="anchor" href="#summary">#</a>
</h2>
<p>With 3.0.0, we&rsquo;ve brought remote functions to the front and center of StateFun. This is done by a new remote function protocol that:</p>
<ol>
<li>✅ ⠀Allows registering a new function or changing the state definitions of an existing function to happen dynamically without any downtime, and</li>
<li>✅ ⠀Provides a cross-language type system, which comes along with a few built-in primitive types, that can be used for messaging and state.</li>
</ol>
<p>A new Java SDK was added for remote functions to extend the array of supported languages to also include all JVM based languages.
The language SDKs now have unified concepts and constructs in their APIs so that they will all feel familiar to work with
when switching around languages for your functions. In upcoming releases, the community is also looking forward to
continuing building on top of the new remote function protocol to provide an even more language SDKs, such as Golang.</p>
<h2 id="release-resources">
Release Resources
<a class="anchor" href="#release-resources">#</a>
</h2>
<p>The binary distribution and source artifacts are now available on the updated <a href="https://flink.apache.org/downloads.html">Downloads</a>
page of the Flink website, and the most recent Python SDK distribution is available on <a href="https://pypi.org/project/apache-flink-statefun/">PyPI</a>.
You can also find official StateFun Docker images of the new version on <a href="https://hub.docker.com/r/apache/flink-statefun">Dockerhub</a>.</p>
<p>For more details, check the <a href="//nightlies.apache.org/flink/flink-statefun-docs-release-3.0/">updated documentation</a> and the
<a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12315522&amp;version=12348822">release notes</a>
for a detailed list of changes and new features if you plan to upgrade your setup to Stateful Functions 3.0.0.
We encourage you to download the release and share your feedback with the community through the <a href="https://flink.apache.org/community.html#mailing-lists">Flink mailing lists</a>
or <a href="https://issues.apache.org/jira/browse/">JIRA</a></p>
<h2 id="list-of-contributors">
List of Contributors
<a class="anchor" href="#list-of-contributors">#</a>
</h2>
<p>The Apache Flink community would like to thank all contributors that have made this release possible:</p>
<pre tabindex="0"><code>Authuir, Chesnay Schepler, David Anderson, Dian Fu, Frans King, Galen Warren, Guillaume Vauvert, Igal Shilman, Ismaël Mejía, Kartik Khare, Konstantin Knauf, Marta Paes Moreira, Patrick Lucas, Patrick Wiener, Rafi Aroch, Robert Metzger, RocMarshal, Seth Wiesman, Siddique Ahmad, SteNicholas, Stephan Ewen, Timothy Bess, Tymur Yarosh, Tzu-Li (Gordon) Tai, Ufuk Celebi, abc863377, billyrrr, congxianqiu, danp11, hequn8128, kaibo, klion26, morsapaes, slinkydeveloper, wangchao, wangzzu, winder
</code></pre><p>If you’d like to get involved, we’re always <a href="https://github.com/apache/flink-statefun#contributing">looking for new contributors</a>.</p>
</p>
</article>
<div class="edit-this-page">
<p>
<a href="https://cwiki.apache.org/confluence/display/FLINK/Flink+Translation+Specifications">Want to contribute translation?</a>
</p>
<p>
<a href="//github.com/apache/flink-web/edit/asf-site/docs/content/posts/2021-04-15-release-statefun-3.0.0.md">
Edit This Page<i class="fa fa-edit fa-fw"></i>
</a>
</p>
</div>
</section>
<aside class="book-toc">
<nav id="TableOfContents"><h3>On This Page <a href="javascript:void(0)" class="toc" onclick="collapseToc()"><i class="fa fa-times" aria-hidden="true"></i></a></h3>
<ul>
<li>
<ul>
<li><a href="#background">Background</a></li>
<li><a href="#new-features">New Features</a>
<ul>
<li><a href="#unified-language-sdks">Unified Language SDKs</a></li>
<li><a href="#cross-language-type-system">Cross-Language Type System</a></li>
<li><a href="#dynamic-registration-of-state-and-functions">Dynamic Registration of State and Functions</a></li>
</ul>
</li>
<li><a href="#summary">Summary</a></li>
<li><a href="#release-resources">Release Resources</a></li>
<li><a href="#list-of-contributors">List of Contributors</a></li>
</ul>
</li>
</ul>
</nav>
</aside>
<aside class="expand-toc hidden">
<a class="toc" onclick="expandToc()" href="javascript:void(0)">
<i class="fa fa-bars" aria-hidden="true"></i>
</a>
</aside>
</main>
<footer>
<div class="separator"></div>
<div class="panels">
<div class="wrapper">
<div class="panel">
<ul>
<li>
<a href="https://flink-packages.org/">flink-packages.org</a>
</li>
<li>
<a href="https://www.apache.org/">Apache Software Foundation</a>
</li>
<li>
<a href="https://www.apache.org/licenses/">License</a>
</li>
<li>
<a href="/zh/">
<i class="fa fa-globe" aria-hidden="true"></i>&nbsp;中文版
</a>
</li>
</ul>
</div>
<div class="panel">
<ul>
<li>
<a href="/what-is-flink/security">Security</a-->
</li>
<li>
<a href="https://www.apache.org/foundation/sponsorship.html">Donate</a>
</li>
<li>
<a href="https://www.apache.org/foundation/thanks.html">Thanks</a>
</li>
</ul>
</div>
<div class="panel icons">
<div>
<a href="/posts">
<div class="icon flink-blog-icon"></div>
<span>Flink blog</span>
</a>
</div>
<div>
<a href="https://github.com/apache/flink">
<div class="icon flink-github-icon"></div>
<span>Github</span>
</a>
</div>
<div>
<a href="https://twitter.com/apacheflink">
<div class="icon flink-twitter-icon"></div>
<span>Twitter</span>
</a>
</div>
</div>
</div>
</div>
<hr/>
<div class="container disclaimer">
<p>The contents of this website are © 2024 Apache Software Foundation under the terms of the Apache License v2. Apache Flink, Flink, and the Flink logo are either registered trademarks or trademarks of The Apache Software Foundation in the United States and other countries.</p>
</div>
</footer>
</body>
</html>