<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oli Makhasoeva</title>
    <description>The latest articles on DEV Community by Oli Makhasoeva (@oli_kitty).</description>
    <link>https://dev.to/oli_kitty</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F684640%2F2dd3eadc-2d40-4ab2-9c20-b8f3f61ac2b1.JPG</url>
      <title>DEV Community: Oli Makhasoeva</title>
      <link>https://dev.to/oli_kitty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oli_kitty"/>
    <language>en</language>
    <item>
      <title>M12 invests in the Future of Stream Processing with Bytewax</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Wed, 09 Aug 2023 16:25:50 +0000</pubDate>
      <link>https://dev.to/bytewax/m12-invests-in-the-future-of-stream-processing-with-bytewax-3n43</link>
      <guid>https://dev.to/bytewax/m12-invests-in-the-future-of-stream-processing-with-bytewax-3n43</guid>
      <description>&lt;p&gt;At Bytewax, we're passionate about the power of real-time data. With AI and automation on the rise, accessing data instantly isn't just a cool perk—it's becoming a necessity. Our mission is to build software that will strip away the complexities of streaming and make it accessible for &lt;strong&gt;every developer&lt;/strong&gt; to build real-time data applications.&lt;/p&gt;

&lt;p&gt;We started with the Rust powered, open source Python stream processor, &lt;a href="https://github.com/bytewax/bytewax"&gt;Bytewax&lt;/a&gt;, which is now a year and a half old, debuting in February 2022. Since starting the project we have grown and matured the Bytewax open source offering to include persistent state, different windowing configurations, and new operators for increased performance and scalability. We have also focused on bettering the developer experience from integration to deployment with our deployment tool, &lt;a href="https://dev.to/docs/deployment/waxctl"&gt;waxctl&lt;/a&gt;, the ability to rescale without losing data stored in state, and the ability to connect to various input and output sources as well as build your own.&lt;/p&gt;

&lt;p&gt;We are excited to announce a new partner along our journey in M12/GitHub with their investment in Bytewax to support further development on the open source as well as the development of &lt;a href="https://dev.to/platform"&gt;&lt;strong&gt;the Bytewax Platform&lt;/strong&gt;&lt;/a&gt;, which will help businesses scale out their Bytewax usage starting with features like disaster recovery, collaboration and observability tools and a management layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Bytewax Supports AI and Real-Time Applications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The world has moved into a new wave of computing where businesses power their operations and consumer interactions with AI. Sophisticated AI models require a real-time understanding of the world to make accurate decisions. What is often referred to as real-time ML is when a system reacts in real-time with a decision powered by an ML model to the inputs it receives. Stream processing and more importantly &lt;strong&gt;stream processing with a Python interface&lt;/strong&gt; is pivotal for Real-time ML in order to transform data into features for models.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about real-time ML with Bytewax in &lt;a href="https://dev.to/blog/real-time-ml"&gt;our blog post here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many other use cases currently being powered by Bytewax from monitoring and reacting to &lt;a href="https://dev.to/blog/online-machine-learning-in-practice-interactive-dashboards-to-detect-data-anomalies-in-real-time"&gt;IoT sensors&lt;/a&gt; for vehicle fleets or across the energy grid, to monitoring &lt;a href="https://dev.to/blog/real-time-stock-prices-with-numpy"&gt;market data&lt;/a&gt; or analyzing &lt;a href="https://dev.to/blog/aws-anomaly-detection"&gt;infrastructure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Investment: A Vote of Confidence&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Microsoft is known for its investments in &lt;a href="https://devblogs.microsoft.com/python/supporting-the-python-community/"&gt;Python&lt;/a&gt; and &lt;a href="https://blogs.microsoft.com/blog/2023/01/23/microsoftandopenaiextendpartnership/"&gt;AI&lt;/a&gt;. Creating partnerships with pivotal developers and teams that are moving the industry forward. Their investment in Bytewax is a vote of confidence towards the Bytewax vision and mission and the importance of stream processing in the next wave of computing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We believe that Zander and the Bytewax team are building a cutting edge tool that simplifies event and stream processing, and appreciate their thoughtful technical approach leveraging a Python framework to build highly scalable streaming dataflows” said Priyanka Mitra, Partner at M12 and co-founder of the M12 GitHub Fund. “We are impressed with their engagement of the open-source community and are committed to supporting Bytewax in accomplishing their mission, especially as they explore cutting edge AI and ML use cases” she added.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Future Bytewax&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Microsoft investment will help Bytewax establish a thriving community around the open source project and build out features for the paid platform to support adoption of the technology. We have been working to solve exceptionally hard problems like rescaling dataflows and cloud backup for disaster recovery as well as improving performance. We are excited to continue to bring features like these to Bytewax with a simple user interface and low complexity to support users across all stages of their journey.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect with us&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We would love to hear from our users and any Python and streaming enthusiasts on how we can increase our support for workloads and Python development patterns. Please feel free to reach out via our &lt;a href="https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-vkos2f6r-_SeT9pF2~n9ArOaeI3ND2w"&gt;slack community&lt;/a&gt; or the &lt;a href="https://github.com/bytewax/bytewax"&gt;GitHub repo&lt;/a&gt;. We would also like to take this opportunity to thank our users, investors, and community for their continued support! If you like what we are building, please &lt;a href="https://github.com/bytewax/bytewax"&gt;⭐ the repo&lt;/a&gt; 😀.&lt;/p&gt;

</description>
      <category>investment</category>
      <category>streaming</category>
    </item>
    <item>
      <title>Bytewax v0.16.2 is out!</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Thu, 08 Jun 2023 20:35:31 +0000</pubDate>
      <link>https://dev.to/bytewax/bytewax-v0162-is-out-1dbb</link>
      <guid>https://dev.to/bytewax/bytewax-v0162-is-out-1dbb</guid>
      <description>&lt;p&gt;🎉 Exciting News from Bytewax! 🎉&lt;/p&gt;

&lt;p&gt;We're thrilled to announce the release of Bytewax v0.16.2!&lt;/p&gt;

&lt;p&gt;Firstly, support for Windows builds is here! 🖥️&lt;/p&gt;

&lt;p&gt;This is a significant step forward not only because it makes Bytewax more accessible to developers across different platforms but also because we're particularly excited to welcome the first contribution from a member of our community Jim Zhang &lt;a href="https://github.com/bytewax/bytewax/pull/249"&gt;@zzl221000&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;A big shout-out to Jim!!!&lt;/p&gt;

&lt;p&gt;In addition to Windows support, v0.16.2 also introduces a CSVInput subclass of FileInput, further expanding the versatility of Bytewax.&lt;/p&gt;

&lt;p&gt;Here's a quick rundown of what's changed in this release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/bytewax/bytewax/pull/244"&gt;PyO3 has been updated by @whoahbot&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bytewax/bytewax/pull/245"&gt;Added a _CSVSource and CSVInput subclass of FileInput by @awmatheson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bytewax/bytewax/pull/247"&gt;Fixed an encoder issue by @Psykopear&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bytewax/bytewax/pull/249"&gt;Windows build support by @zzl221000&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're OSS and incredibly grateful for the community's contributions&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GJfYK3dE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-1lhq9bxbr-T3CXxR_9RIUGb4qcBK26Qw" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GJfYK3dE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-1lhq9bxbr-T3CXxR_9RIUGb4qcBK26Qw" alt="Share" width="" height=""&gt;&lt;/a&gt; what you're building with Bytewax, and happy coding! 🚀 Check out the changes on &lt;a href="https://github.com/bytewax/bytewax/"&gt;our GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Bytewax at Data Science Summit. Interactive Dashboards To Detect Data Anomalies In Real Time</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Wed, 24 May 2023 21:41:03 +0000</pubDate>
      <link>https://dev.to/bytewax/bytewax-at-data-science-summit-interactive-dashboards-to-detect-data-anomalies-in-real-time-5e3c</link>
      <guid>https://dev.to/bytewax/bytewax-at-data-science-summit-interactive-dashboards-to-detect-data-anomalies-in-real-time-5e3c</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NOnrBjg1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdl0zu6hnx1png37c1gt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NOnrBjg1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdl0zu6hnx1png37c1gt.png" alt="talk invite" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Science Summit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dssconf.pl/en/"&gt;Data Science Summit&lt;/a&gt; is the largest and oldest independent data science conference in the CEE region. This year, we are joining them online and our CEO, Zander Matheson, is presenting! For the sixth time Data Science Summit shares knowledge in topics ranging from analysis and processing (including big data), implementation issues to visualisation (BI) and management topics. This year's edition of the most important Data Science event in Poland dedicated to Machine Learning!&lt;/p&gt;

&lt;p&gt;10 tracks, 100+ talks, the agenda is packed with cutting-edge insights 💡&lt;/p&gt;

&lt;p&gt;🎟️ Use code DSSML23RP20 until 09.06.2023 to grab a Standard or PRO ticket at a 20% discount&lt;/p&gt;

&lt;p&gt;Here are details of the talk Zander is presenting:&lt;/p&gt;

&lt;h2&gt;
  
  
  Interactive dashboards to detect data anomalies in real time
&lt;/h2&gt;

&lt;p&gt;Join Zander for a technical exploration of crafting interactive dashboards that employ online machine learning algorithms for real-time anomaly detection across hundreds of sensors. He will guide you through how to set up a development environment with a streaming system (Kafka or similar), load sensor data to the streaming system with Bytewax, and write a dataflow using River that will transform the data and use different anomaly detection algorithms to determine if there are anomalies in the sensor data. The icing on the cake? Visualize all these complex processes on a dynamic, real-time dashboard using Rerun! Equip yourself with the tools and knowledge to monitor and react to data anomalies as they happen. Come, experience the power of Python in data anomaly detection and interactive visualization in real time!&lt;/p&gt;

&lt;p&gt;If this abstract sounds interesting, you might want to check out these blogs: &lt;a href="https://bytewax.io/blog/data-visualization-with-rerun"&gt;Real-Time Anomaly Detection Visualization with Bytewax and Rerun&lt;/a&gt; and &lt;a href="https://bytewax.io/blog/online-machine-learning-iot#online-machine-learning-in-python"&gt;Online Machine Learning for IoT&lt;/a&gt;. The talk is going to go beyond these but it covers same domains.&lt;/p&gt;

&lt;p&gt;We are looking forward to exchange knowledge, share our ideas and learn from the experiences of other attendees and speakers. Stay tuned for updates from &lt;a href="https://ml.dssconf.pl/en/"&gt;the conference!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>conference</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Easy yet flexible way to display child routes in tabs with Vue 3</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Tue, 09 May 2023 18:22:17 +0000</pubDate>
      <link>https://dev.to/bytewax/easy-yet-flexible-way-to-display-child-routes-in-tabs-with-vue-3-2ng8</link>
      <guid>https://dev.to/bytewax/easy-yet-flexible-way-to-display-child-routes-in-tabs-with-vue-3-2ng8</guid>
      <description>&lt;p&gt;Hello, I'm Konrad Sieńkowski and I am a front-end developer &amp;amp; UI designer here at Bytewax. I want to share with you something that I worked on recently. In this article, I'll walk through the steps to set up a new Vue application, configure the router for nested routes, create the AppTabs.vue component, and customize your tabs using route meta fields for labels and icons. By the end, you'll know how to make an easy yet flexible solution for displaying child routes in tabs. So, let's dive in!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For those eager to dive in, check out the &lt;a href="https://github.com/konradsienkowski/vue-3-child-route-tabs/"&gt;project repository&lt;/a&gt; on Github.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;First of all, we're going to create a fresh, new application using &lt;code&gt;&amp;amp;gt; npm init vue@latest&lt;/code&gt;. The &lt;code&gt;vue-create&lt;/code&gt; tool is going to ask you about including optional features in the project. The only one required for that tutorial is &lt;strong&gt;Vue Router&lt;/strong&gt;. I chose Typescript &amp;amp; Prettier as well, but it's up to your personal preferences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing routes &amp;amp; structure
&lt;/h2&gt;

&lt;p&gt;Once you follow the instructions on installing dependencies and running the app, you can start customizing the application. My first step was to simplify &lt;code&gt;app.vue&lt;/code&gt; a bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;template&amp;amp;gt;
  &amp;amp;lt;nav&amp;amp;gt;
    &amp;amp;lt;RouterLink to=&amp;amp;quot;/&amp;amp;quot;&amp;amp;gt;Home&amp;amp;lt;/RouterLink&amp;amp;gt;
    &amp;amp;lt;RouterLink to=&amp;amp;quot;/tabs&amp;amp;quot;&amp;amp;gt;Tabs demo&amp;amp;lt;/RouterLink&amp;amp;gt;
  &amp;amp;lt;/nav&amp;amp;gt;

  &amp;amp;lt;RouterView /&amp;amp;gt;
&amp;amp;lt;/template&amp;amp;gt;

&amp;amp;lt;script setup lang=&amp;amp;quot;ts&amp;amp;quot;&amp;amp;gt;
import { RouterLink, RouterView } from &amp;amp;apos;vue-router&amp;amp;apos;
&amp;amp;lt;/script&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we're focusing on nested/child routes in this article, there's no need to spend much time on the homepage. I've also renamed default &lt;code&gt;AboutView.vue&lt;/code&gt; to &lt;code&gt;TabsView.vue&lt;/code&gt; and created bunch of example views in &lt;code&gt;views/tabs&lt;/code&gt;, called &lt;code&gt;TabsAbout.vue&lt;/code&gt;, &lt;code&gt;TabsBlog.vue&lt;/code&gt;, &lt;code&gt;TabsContact.vue&lt;/code&gt;, &lt;code&gt;TabsRelated.vue&lt;/code&gt;. We're going to include them in our routes structure in the next step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- views
-- tabs
--- TabsAbout.vue
--- TabsBlog.vue
--- TabsContact.vue
--- TabsRelated.vue
-- HomeView.vue
-- TabsView.vue

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we have a simple structure for our views/pages, now it's time to include them in router configuration. Let's open &lt;code&gt;router/index.ts&lt;/code&gt; now and adjust it to our needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createRouter, createWebHistory } from &amp;amp;apos;vue-router&amp;amp;apos;
import HomeView from &amp;amp;apos;../views/HomeView.vue&amp;amp;apos;

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: &amp;amp;apos;/&amp;amp;apos;,
      name: &amp;amp;apos;home&amp;amp;apos;,
      component: HomeView
    },
    {
      path: &amp;amp;apos;/tabs&amp;amp;apos;,
      name: &amp;amp;apos;tabs&amp;amp;apos;,
      component: () =&amp;amp;gt; import(&amp;amp;apos;../views/TabsView.vue&amp;amp;apos;),
      children: [
        {
          name: &amp;amp;apos;about&amp;amp;apos;,
          path: &amp;amp;apos;&amp;amp;apos;,
          component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsAbout.vue&amp;amp;apos;),
        },
        {
          name: &amp;amp;apos;blog&amp;amp;apos;,
          path: &amp;amp;apos;blog&amp;amp;apos;,
          component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsBlog.vue&amp;amp;apos;),
        },
        {
          name: &amp;amp;apos;contact&amp;amp;apos;,
          path: &amp;amp;apos;contact&amp;amp;apos;,
          component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsContact.vue&amp;amp;apos;),
        },
        {
          name: &amp;amp;apos;related&amp;amp;apos;,
          path: &amp;amp;apos;related&amp;amp;apos;,
          component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsRelated.vue&amp;amp;apos;),
        },
      ]
    }
  ]
})

export default router

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, our application has nested/children routes which we can use to display tabs in the component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tabs component
&lt;/h2&gt;

&lt;p&gt;In this step, we're going to create our tab component, include it in the first-level route view and then extend it with additional features. First of all, we're going to create file called &lt;code&gt;AppTabs.vue&lt;/code&gt; in &lt;code&gt;components&lt;/code&gt; directory. Since our component is going to be flexible and might be used in different routes, we're following &lt;a href="https://v2.vuejs.org/v2/style-guide/?redirect=true#Base-component-names-strongly-recommended"&gt;Vue naming convention&lt;/a&gt; for base components.&lt;/p&gt;

&lt;p&gt;Let's start from the &lt;code&gt;&amp;amp;lt;script setup&amp;amp;gt;&lt;/code&gt; section. We're using &lt;code&gt;useRouter()&lt;/code&gt; composable there to access the router instance. Then, we're using it to define &lt;code&gt;tabs&lt;/code&gt; computed property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;script setup lang=&amp;amp;quot;ts&amp;amp;quot;&amp;amp;gt;
import { computed, type ComputedRef } from &amp;amp;apos;vue&amp;amp;apos;
import { useRouter, RouterView, type RouteRecordRaw } from &amp;amp;apos;vue-router&amp;amp;apos;

// Use children routes for the tabs
const router = useRouter()
const tabs: ComputedRef&amp;amp;lt;RouteRecordRaw[] | undefined&amp;amp;gt; = computed(() =&amp;amp;gt; {
  const currentRoute = router.currentRoute.value.name
  return router.options.routes?.find(
    (route) =&amp;amp;gt;
      route.name === currentRoute || route.children?.find((child) =&amp;amp;gt; child.name === currentRoute)
  )?.children
})
&amp;amp;lt;/script&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After getting the current route name using &lt;code&gt;router.currentRoute&lt;/code&gt; property, we're using it to find it within the routes array (either within top-level routes and their children) and return its children routes. Now it's time to include it in the component template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;template&amp;amp;gt;
  &amp;amp;lt;div class=&amp;amp;quot;tabs&amp;amp;quot; v-if=&amp;amp;quot;tabs&amp;amp;quot;&amp;amp;gt;
    &amp;amp;lt;nav class=&amp;amp;quot;tabs__nav&amp;amp;quot;&amp;amp;gt;
      &amp;amp;lt;RouterLink
        v-for=&amp;amp;quot;tab in tabs&amp;amp;quot;
        :key=&amp;amp;quot;tab.name&amp;amp;quot;
        class=&amp;amp;quot;tabs__nav-item&amp;amp;quot;
        :to=&amp;amp;quot;{ name: tab.name }&amp;amp;quot;
      &amp;amp;gt;
        {{ tab.name }}
      &amp;amp;lt;/RouterLink&amp;amp;gt;
    &amp;amp;lt;/nav&amp;amp;gt;
    &amp;amp;lt;div class=&amp;amp;quot;tabs__wrapper&amp;amp;quot;&amp;amp;gt;
      &amp;amp;lt;RouterView v-slot=&amp;amp;quot;{ Component }&amp;amp;quot;&amp;amp;gt;
        &amp;amp;lt;Transition name=&amp;amp;quot;fade&amp;amp;quot; mode=&amp;amp;quot;out-in&amp;amp;quot;&amp;amp;gt;
          &amp;amp;lt;component :is=&amp;amp;quot;Component&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;/component&amp;amp;gt;
        &amp;amp;lt;/Transition&amp;amp;gt;
      &amp;amp;lt;/RouterView&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;
  &amp;amp;lt;/div&amp;amp;gt;
&amp;amp;lt;/template&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;code&gt;&amp;amp;lt;div&amp;amp;gt;&lt;/code&gt; wrapper, we have two parts of our component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;navigation / tabs, where we iterate over output of &lt;code&gt;tabs&lt;/code&gt; computed getter and display links of children routes,&lt;/li&gt;
&lt;li&gt;tabs wrapper, where we're using native &lt;code&gt;&amp;amp;lt;RouterView&amp;amp;gt;&lt;/code&gt; and its v-slot api to &lt;a href="https://router.vuejs.org/guide/advanced/transitions.html#transitions"&gt;wrap nested route's content in &lt;code&gt;&amp;amp;lt;Transition&amp;amp;gt;&lt;/code&gt; component&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can include our component in the &lt;code&gt;TabsView.vue&lt;/code&gt; code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;template&amp;amp;gt;
  &amp;amp;lt;div class=&amp;amp;quot;view&amp;amp;quot;&amp;amp;gt;
    &amp;amp;lt;AppTabs /&amp;amp;gt;
  &amp;amp;lt;/div&amp;amp;gt;
&amp;amp;lt;/template&amp;amp;gt;

&amp;amp;lt;script setup lang=&amp;amp;quot;ts&amp;amp;quot;&amp;amp;gt;
import AppTabs from &amp;amp;apos;@/components/AppTabs.vue&amp;amp;apos;
&amp;amp;lt;/script&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And take a look at the result: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cSpP8Rkh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://images.production.bytewax.io/Vite_App_2f6e016637.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cSpP8Rkh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://images.production.bytewax.io/Vite_App_2f6e016637.gif" alt="Vite-App.gif" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending &amp;amp; styling up the tabs
&lt;/h2&gt;

&lt;p&gt;Our tabs work nice, and we can easily include them in any view that has child routes. However, the tabs navigation uses &lt;code&gt;route.name&lt;/code&gt; as a link label, and &lt;a href="https://router.vuejs.org/guide/essentials/named-routes.html"&gt;route names&lt;/a&gt; should rather remain simple and easy to use. We can extend our solution with route props to include custom tab label &amp;amp; icon for each child route.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use custom route props
&lt;/h3&gt;

&lt;p&gt;Before extending our component's code, let's add &lt;a href="https://router.vuejs.org/guide/advanced/meta.html"&gt;meta field&lt;/a&gt; to each nested route in &lt;code&gt;router/index.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;children: [
  {
    name: &amp;amp;apos;about&amp;amp;apos;,
    path: &amp;amp;apos;&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsAbout.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;About&amp;amp;apos; }
  },
  {
    name: &amp;amp;apos;blog&amp;amp;apos;,
    path: &amp;amp;apos;blog&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsBlog.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;Blog&amp;amp;apos; }
  },
  {
    name: &amp;amp;apos;contact&amp;amp;apos;,
    path: &amp;amp;apos;contact&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsContact.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;Contact&amp;amp;apos; }
  },
  {
    name: &amp;amp;apos;related&amp;amp;apos;,
    path: &amp;amp;apos;related&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsRelated.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;Related&amp;amp;apos; }
  },
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can use &lt;code&gt;tabLabel&lt;/code&gt; value in our &lt;code&gt;AppTabs.vue&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;RouterLink
  v-for=&amp;amp;quot;tab in tabs&amp;amp;quot;
  :key=&amp;amp;quot;tab.name&amp;amp;quot;
  class=&amp;amp;quot;tabs__nav-item&amp;amp;quot;
  :to=&amp;amp;quot;{ name: tab.name }&amp;amp;quot;
&amp;amp;gt;
  &amp;amp;lt;span class=&amp;amp;quot;tabs__nav-label&amp;amp;quot; v-if=&amp;amp;quot;tab.meta?.tabLabel&amp;amp;quot;&amp;amp;gt;{{ tab.meta.tabLabel }}&amp;amp;lt;/span&amp;amp;gt;
&amp;amp;lt;/RouterLink&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add material icons to tabs navigation
&lt;/h3&gt;

&lt;p&gt;Our tabs navigation is going to look better with icons. Let's install Google's Material Symbols library using npm package: &lt;code&gt;npm install material-symbols@latest&lt;/code&gt; and include it in &lt;code&gt;main.ts&lt;/code&gt; (&lt;code&gt;main.js&lt;/code&gt; if you're not using typescript):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createApp } from &amp;amp;apos;vue&amp;amp;apos;
import App from &amp;amp;apos;./App.vue&amp;amp;apos;
import router from &amp;amp;apos;./router&amp;amp;apos;

import &amp;amp;apos;material-symbols/outlined.css&amp;amp;apos;;
import &amp;amp;apos;./assets/main.css&amp;amp;apos;

const app = createApp(App)

app.use(router)

app.mount(&amp;amp;apos;#app&amp;amp;apos;)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can add &lt;code&gt;tabIcon&lt;/code&gt; properties to route meta fields, filling it with the icon codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;children: [
  {
    name: &amp;amp;apos;about&amp;amp;apos;,
    path: &amp;amp;apos;&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsAbout.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;About&amp;amp;apos;, tabIcon: &amp;amp;apos;group&amp;amp;apos; }
  },
  {
    name: &amp;amp;apos;blog&amp;amp;apos;,
    path: &amp;amp;apos;blog&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsBlog.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;Blog&amp;amp;apos;, tabIcon: &amp;amp;apos;feed&amp;amp;apos; }
  },
  {
    name: &amp;amp;apos;contact&amp;amp;apos;,
    path: &amp;amp;apos;contact&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsContact.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;Contact&amp;amp;apos;, tabIcon: &amp;amp;apos;email&amp;amp;apos; }
  },
  {
    name: &amp;amp;apos;related&amp;amp;apos;,
    path: &amp;amp;apos;related&amp;amp;apos;,
    component: () =&amp;amp;gt; import(&amp;amp;apos;../views/tabs/TabsRelated.vue&amp;amp;apos;),
    meta: { tabLabel: &amp;amp;apos;Related&amp;amp;apos;, tabIcon: &amp;amp;apos;star&amp;amp;apos; }
  },
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we're ready to include them in the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;RouterLink
  v-for=&amp;amp;quot;tab in tabs&amp;amp;quot;
  :key=&amp;amp;quot;tab.name&amp;amp;quot;
  class=&amp;amp;quot;tabs__nav-item&amp;amp;quot;
  :to=&amp;amp;quot;{ name: tab.name }&amp;amp;quot;
&amp;amp;gt;
  &amp;amp;lt;span class=&amp;amp;quot;tabs__nav-icon material-symbols-outlined&amp;amp;quot; v-if=&amp;amp;quot;tab.meta?.tabIcon&amp;amp;quot;&amp;amp;gt;{{
    tab.meta.tabIcon
  }}&amp;amp;lt;/span&amp;amp;gt;
  &amp;amp;lt;span class=&amp;amp;quot;tabs__nav-label&amp;amp;quot; v-if=&amp;amp;quot;tab.meta?.tabLabel&amp;amp;quot;&amp;amp;gt;{{ tab.meta.tabLabel }}&amp;amp;lt;/span&amp;amp;gt;
&amp;amp;lt;/RouterLink&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done! We have custom icons &amp;amp; labels based on route meta fields displayed in our Tabs component. Now it's time to add final styling touch with CSS. &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1TDttIo9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://images.production.bytewax.io/icons_e127e03029.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1TDttIo9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://images.production.bytewax.io/icons_e127e03029.png" alt="icons.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Styling up the component
&lt;/h2&gt;

&lt;p&gt;You can style up the component on your own, customizing it fully to your needs or use code below including it in &lt;code&gt;AppTabs.vue&lt;/code&gt; below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;lt;style&amp;amp;gt;
.tabs {
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 0.5rem;
}
.tabs__wrapper {
  padding: 1.5rem 2rem 2rem 2rem;
}
.tabs__nav {
  display: flex;
  flex-direction: row;
  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
}
.tabs__nav-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: nowrap;
  text-decoration: none;
  padding: 1rem;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  color: rgba(0, 0, 0, 0.87);
  transition: border-color 0.25s ease-in-out;
}
.tabs__nav-icon {
  margin-right: 0.5rem;
  color: rgba(0, 0, 0, 0.38);
}
.tabs__nav-item:hover {
  border-color: #ccc;
}
.tabs__nav-item.router-link-exact-active {
  border-color: var(--green);
  font-weight: 600;
}
&amp;amp;lt;/style&amp;amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: Following &lt;a href="https://getbem.com/naming/"&gt;BEM naming convention&lt;/a&gt; is easier using SCSS but I didn't want to fill the example with extra dependencies.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our tab component looks pretty slick now: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3LfxBnHl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://images.production.bytewax.io/Vite_App_2_739c51d2d1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3LfxBnHl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://images.production.bytewax.io/Vite_App_2_739c51d2d1.gif" alt="Vite-App-2.gif" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Instead of conclusion
&lt;/h2&gt;

&lt;p&gt;Now, I encourage you to give it a try, explore further customizations, and share your experiences and improvements with &lt;a href="https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-1lhq9bxbr-T3CXxR_9RIUGb4qcBK26Qw"&gt;our community&lt;/a&gt;. Let's continue building more efficient and elegant applications together!&lt;/p&gt;

</description>
      <category>vue</category>
      <category>ui</category>
    </item>
    <item>
      <title>Lessons we learned while building a stateful Kafka connector and tips for creating yours</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Wed, 03 May 2023 20:16:54 +0000</pubDate>
      <link>https://dev.to/bytewax/lessons-we-learned-while-building-a-stateful-kafka-connector-and-tips-for-creating-yours-157b</link>
      <guid>https://dev.to/bytewax/lessons-we-learned-while-building-a-stateful-kafka-connector-and-tips-for-creating-yours-157b</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3zQ82qXy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjksww988bqqyata57p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3zQ82qXy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjksww988bqqyata57p8.png" alt="Bytewax" width="798" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Bytewax framework is a flexible tool designed to meet the challenges faced by Python developers in today's data-driven world. It aims to provide seamless integrations and time-saving shortcuts for data engineers dealing with streaming data, making their work more efficient and effective. One of the important sides of developing Bytewax is input connectors. These connectors help in establishing the connection between the external systems and Bytewax to help users in importing data from external systems.&lt;/p&gt;

&lt;p&gt;Here we're going to show how to write a custom input connector by walking through how we wrote &lt;a href="https://github.com/bytewax/bytewax/blob/5d5ec04851c2e254cf1aaf429f4890be3a3ce070/pysrc/bytewax/connectors/kafka.py"&gt;our built-in Kafka input connector&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Writing input connectors for arbitrary systems while supporting failure recovery and strong delivery guarantees requires a solid understanding of how recovery works internal to Bytewax and the chosen output system. We strongly encourage you to use the connectors we have built into &lt;a href="https://bytewax.io/apidocs/bytewax.connectors/index"&gt;&lt;code&gt;bytewax.connectors&lt;/code&gt;&lt;/a&gt; if possible, and read the documentation on their limits.&lt;/p&gt;

&lt;p&gt;If you are interested in writing your own, this article can give you an introduction into some of the decisions involved in writing an input connector for an ordered, partitioned input stream.&lt;/p&gt;

&lt;p&gt;If you need any help at all writing a connector, come say "hi" and ask questions in &lt;a href="https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-1lhq9bxbr-T3CXxR_9RIUGb4qcBK26Qw"&gt;the Bytewax community Slack&lt;/a&gt;! We are happy to help!&lt;/p&gt;

&lt;h2&gt;
  
  
  Partitions
&lt;/h2&gt;

&lt;p&gt;Writing a subclass for &lt;a href="https://bytewax.io/apidocs/bytewax.inputs#bytewax.inputs.PartitionedInput"&gt;&lt;code&gt;bytewax.inputs.PartitionedInput&lt;/code&gt;&lt;/a&gt; is the core API for writing an input connector when you have an input that has a fixed number of &lt;strong&gt;partitions&lt;/strong&gt;. A partition is a "sub-stream" of data that can be read concurrently and independently.&lt;/p&gt;

&lt;p&gt;To write a &lt;code&gt;PartitionedInput&lt;/code&gt; subclass, you need to answer three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How many partitions are there?&lt;/li&gt;
&lt;li&gt;How can I build a source that reads a single partition?&lt;/li&gt;
&lt;li&gt;How can I rewind a partition and read from a specific item?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is done via the abstract methods &lt;code&gt;list_parts&lt;/code&gt;, &lt;code&gt;build_part&lt;/code&gt;, and the &lt;code&gt;resume_state&lt;/code&gt; variable respectively.&lt;/p&gt;

&lt;p&gt;We're going to use the &lt;a href="https://github.com/confluentinc/confluent-kafka-python"&gt;&lt;code&gt;confluent-kafka&lt;/code&gt;&lt;/a&gt; package to actually communicate with the Kafka cluster. Let's import all the things we'll need for this input source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from typing import Dict, Iterable

from confluent_kafka import (
    Consumer,
    KafkaError,
    OFFSET_BEGINNING,
    TopicPartition,
)
from confluent_kafka.admin import AdminClient

from bytewax.inputs import PartitionedInput, StatefulSource

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our KafkaInput connector is going to read from a specific set of topics on a cluster. First, let's define our class and write a constructor that takes all the arguments that make sense for configuring this specific kind of input source. This is going to be the public entry point to this connector, and is what you'll pass to the &lt;a href="https://bytewax.io/apidocs/bytewax.dataflow#bytewax.dataflow.Dataflow.input"&gt;&lt;code&gt;bytewax.dataflow.Dataflow.input&lt;/code&gt;&lt;/a&gt; operator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class KafkaInput(PartitionedInput):
    def __init__ (
        self,
        brokers: Iterable[str],
        topics: Iterable[str],
        tail: bool = True,
        starting_offset: int = OFFSET_BEGINNING,
        add_config: Dict[str, str] = None,
    ):
        add_config = add_config or {}

        if isinstance(brokers, str):
            raise TypeError(&amp;amp;quot;brokers must be an iterable and not a string&amp;amp;quot;)
        self

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing Partitions
&lt;/h3&gt;

&lt;p&gt;Next, let's answer question one: how many partitions are there? Conveniently, &lt;code&gt;confluent-kafka&lt;/code&gt; provides an &lt;a href="https://docs.confluent.io/platform/current/clients/confluent-kafka-python/html/index.html#confluent_kafka.admin.AdminClient.list_topics"&gt;&lt;code&gt;AdminClient.list_topics&lt;/code&gt;&lt;/a&gt; which give you the partition count of each topic, packed deep in a metadata object. The signature of &lt;code&gt;PartitionedInput.list_parts&lt;/code&gt; says it must return a set of strings with IDs of all the partitions. Let's build the &lt;code&gt;AdminClient&lt;/code&gt; using our configuring instance variables and then delegate to a &lt;code&gt;_list_parts&lt;/code&gt; function so we can re-use it if necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Continued
# class KafkaInput(PartitionedInput):
    def list_parts(self):
        config = {
            &amp;amp;quot;bootstrap.servers&amp;amp;quot;: &amp;amp;quot;,&amp;amp;quot;.join(self._brokers),
        }
        config.update(self._add_config)
        client = AdminClient(config)

        return set(_list_parts(client, self._topics))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function unpacks the nested metadata returned from &lt;code&gt;AdminClient.list_topics&lt;/code&gt;, and returns a string that looks like "3-my_topic" for the third partition in the topic &lt;code&gt;my_topic&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def _list_parts(client, topics):
    for topic in topics:
        # List topics one-by-one so if auto-create is turned on,
        # we respect that.
        cluster_metadata = client.list_topics(topic)
        topic_metadata = cluster_metadata.topics[topic]
        if topic_metadata.error is not None:
            raise RuntimeError(
                f&amp;amp;quot;error listing partitions for Kafka topic `{topic!r}`: &amp;amp;quot;
                f&amp;amp;quot;{topic_metadata.error.str()}&amp;amp;quot;
            )
        part_idxs = topic_metadata.partitions.keys()
        for i in part_idxs:
            yield f&amp;amp;quot;{i}-{topic}&amp;amp;quot;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How do you decide what the partition ID string should be? It should be something that globally identifies this partition, hence combining partition number and topic name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PartitionedInput.list_parts&lt;/code&gt; might be called multiple times from multiple workers as a Bytewax cluster is setup and resumed, so it must return exactly the same set of partitions on every call in order to work correctly. Changing numbers of partitions is not currently supported with recovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Partitions
&lt;/h3&gt;

&lt;p&gt;Next, let's answer question two: how can I build a source that reads a single partition? We can use &lt;code&gt;confluent-kafka&lt;/code&gt;'s &lt;a href="https://docs.confluent.io/platform/current/clients/confluent-kafka-python/html/index.html#consumer"&gt;&lt;code&gt;Consumer&lt;/code&gt;&lt;/a&gt; to make a Kafka consumer that will read a specific topic and partition starting from an offset. The signature of &lt;code&gt;PartitionedInput.build_part&lt;/code&gt; takes a specific partition ID (we'll ignore the resume state for now) and must return a stateful source.&lt;/p&gt;

&lt;p&gt;We parse the partition ID to determine which Kafka partition we should be consuming from. (Hence the importance of having a globally unique partition ID.) Then we build a &lt;code&gt;Consumer&lt;/code&gt; that connects to the Kafka cluster, and build our custom &lt;code&gt;_KafkaSource&lt;/code&gt; stateful source. That is where the actual reading of input items happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Continued
# class KafkaInput(PartitionedInput):
    def build_part(self, for_part, resume_state):
        part_idx, topic = for_part.split(&amp;amp;quot;-&amp;amp;quot;, 1)
        part_idx = int(part_idx)
        assert topic in self._topics, &amp;amp;quot;Can&amp;amp;apos;t resume from different set of Kafka topics&amp;amp;quot;

        config = {
            # We&amp;amp;apos;ll manage our own &amp;amp;quot;consumer group&amp;amp;quot; via recovery
            # system.
            &amp;amp;quot;group.id&amp;amp;quot;: &amp;amp;quot;BYTEWAX_IGNORED&amp;amp;quot;,
            &amp;amp;quot;enable.auto.commit&amp;amp;quot;: &amp;amp;quot;false&amp;amp;quot;,
            &amp;amp;quot;bootstrap.servers&amp;amp;quot;: &amp;amp;quot;,&amp;amp;quot;.join(self._brokers),
            &amp;amp;quot;enable.partition.eof&amp;amp;quot;: str(not self._tail),
        }
        config.update(self._add_config)
        consumer = Consumer(config)
        return _KafkaSource(
            consumer, topic, part_idx, self._starting_offset, resume_state
        )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stateful Input Source
&lt;/h2&gt;

&lt;p&gt;What is a stateful source? It is defined by subclassing &lt;a href="https://bytewax.io/apidocs/bytewax.inputs#bytewax.inputs.StatefulSource"&gt;&lt;code&gt;bytewax.inputs.StatefulSource&lt;/code&gt;&lt;/a&gt;. You can think about it as a "snapshot-able Python iterator": something that produces a stream of items via &lt;code&gt;StatefulSource.next&lt;/code&gt;, and also lets the Bytewax runtime ask for a snapshot of the position of the source via &lt;code&gt;StatefulSource.snapshot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;_KafkaSource&lt;/code&gt; is going to read items from a specific Kafka topic's partition. Let's define that class and have a constructor that takes in all the details to start reading that partition: the consumer (already configured to connect to the correct Kafka cluster), the topic, the specific partition index, the default starting offset (beginning or end of the topic), and again we'll ignore the resume state for just another moment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class _KafkaSource(StatefulSource):
    def __init__ (self, consumer, topic, part_idx, starting_offset, resume_state):
        self._offset = resume_state or starting_offset
        # Assign does not activate consumer grouping.
        consumer.assign([TopicPartition(topic, part_idx, self._offset)])
        self._consumer = consumer
        self._topic = topic

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beating heart of the input source is the StatefulSource.next method. It is periodically called by Bytewax and behaves similar to a &lt;a href="https://docs.python.org/3/library/stdtypes.html#iterator.%20__next__"&gt;built-in Python iterator's &lt;code&gt;__next__&lt;/code&gt; method&lt;/a&gt;. It must do one of three things: return a new item to send into the dataflow, return None signaling that there is no data currently but might be later, or raise StopIteration when the partition is complete.&lt;/p&gt;

&lt;p&gt;Consumer.poll gives us a method to ask if there are any new messages on the partition we setup this consumer to follow. And if there are, unpack the data message and return it. Otherwise handle the no data case, the end-of-stream case, or an exceptional error case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Continued
# class _KafkaSource(StatefulSource):
    def next(self):
        msg = self._consumer.poll(0.001) # seconds
        if msg is None:
            return
        elif msg.error() is not None:
            if msg.error().code() == KafkaError._PARTITION_EOF:
                raise StopIteration()
            else:
                raise RuntimeError(
                    f&amp;amp;quot;error consuming from Kafka topic `{self.topic!r}`: {msg.error()}&amp;amp;quot;
                )
        else:
            item = (msg.key(), msg.value())
            # Resume reading from the next message, not this one.
            self._offset = msg.offset() + 1
            return item

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An important thing to note here is that StatefulSource.next must never block. The Bytewax runtime employs a sort of cooperative multitasking, and so each operator must return quickly, even if it has nothing to do, so other operators in the dataflow that do have work can run. Unfortunately, currently there is no way in the Bytewax API to prevent polling of input sources (as input comes from outside the dataflow, Bytewax has no way of knowing when more data is available, so must constantly check). The best practice here is to pause briefly if there is no data to prevent a full spin-loop on no new data, but not so long you block other operators from doing their work.&lt;/p&gt;

&lt;p&gt;There is also a &lt;code&gt;StatefulSource.close&lt;/code&gt; method which enables you to do any well-behaved shutdown when EOF is reached. This is not guaranteed to be called in a failure situation and should not be crucial to the connecting system. In this case, &lt;code&gt;Consumer.close&lt;/code&gt; does graceful shutdown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# class _KafkaSource(StatefulSource):
    def close(self):
        self._consumer.close()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resume State
&lt;/h3&gt;

&lt;p&gt;Lets explain how failure recovery works for input connectors. Bytewax's recovery system allows the dataflow to quickly resume processing and output without needing to replay all input. It does this by periodically snapshot all internal state, input positions, and output positions of the dataflow. Then when it needs to recover after a failure, it loads all state from a recent snapshot, and starts re-playing input items in the same order from the instant of the snapshot and overwriting output items. This will cause the state and output of the dataflow to evolve in the same way during the resume execution as during the previous execution.&lt;/p&gt;

&lt;h4&gt;
  
  
  Snapshotting
&lt;/h4&gt;

&lt;p&gt;So, we need to keep track of the current position somewhere in each partition. Kafka has the concept of message offsets, which is an incrementing immutable integer that is the position of each message. In &lt;code&gt;_KafkaSource.next&lt;/code&gt;, we kept track of the offset of the next message that partition will read via &lt;code&gt;self._offset = msg.offset() + 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Bytewax calls &lt;code&gt;StatefulSource.snapshot&lt;/code&gt; when it needs to record that partition's position and returns that internally stored next message offset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Continued
# class _KafkaSource(StatefulSource):
    def snapshot(self):
        return self._offset

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Resume
&lt;/h4&gt;

&lt;p&gt;On resume after a failure, Bytewax's recovery machinery does the hard work of collecting all the snapshots, finding the ones that represent a coherent set of states across the previous execution's cluster, and threading each bit of snapshot data back through into &lt;code&gt;PartitionedInput.build_part&lt;/code&gt; for the same partition. To properly take advantage of that, your resulting partition must resume reading from the same spot represented by that snapshot.&lt;/p&gt;

&lt;p&gt;Since we were storing the Kafka message offset of the next message to be read in &lt;code&gt;_KafkaSource._offset&lt;/code&gt;, we need to ensure we thread through that message offset back into the &lt;code&gt;Consumer&lt;/code&gt; when it is built. That happens via passing &lt;code&gt;resume_state&lt;/code&gt; into the &lt;code&gt;_KafkaSource&lt;/code&gt; constructor, and it assigning that consumer to start reading from that offset. Looking at that code again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Continued
# class _KafkaSource(StatefulSource):
# def __init__ (self, consumer, topic, part_idx, starting_offset, resume_state):
        self._offset = resume_state or starting_offset
        # Assign does not activate consumer grouping.
        consumer.assign([TopicPartition(topic, part_idx, self._offset)])
        ...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As one extra wrinkle, if there is no resume state for this partition if the partition is being built for the first time, &lt;code&gt;None&lt;/code&gt; will be passed for &lt;code&gt;resume_state&lt;/code&gt; in &lt;code&gt;PartitionedInput.build_part&lt;/code&gt;. In that case, we need to fill in the requested "default starting offset": either "beginning of topic" or "end of topic". In the case where we do have resume state, we should ignore that since we need to start from the specific offset to uphold the recovery contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delivery Guarantees
&lt;/h2&gt;

&lt;p&gt;Let's talk for a moment about how this recovery model with snapshots impacts delivery guarantees. A well-designed input connector on its own can only guarantee that the output of a dataflow to a downstream system is at-least-once: the recovery system will ensure that we replay any input that might not have been output due to where the execution cluster failed, but it requires coordination with the output connector (via something like transactions or two-phase commits) to ensure that the replay does not result in duplicated writes downstream and exactly-once processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Non-Replay-Able Sources
&lt;/h3&gt;

&lt;p&gt;If your input source does not have the ability to replay old data, you can still use it with Bytewax, but your delivery guarantees are limited to at-least-once. For example, listening to an ephemeral SSE or WebSocket stream, you can always start listening, but often the request API does not let you specify an ability to replay missing events. When Bytewax attempts to resume, all the other operators will have their internal state returned to that last coherent snapshot, but since the input sources do not rewind, it will appear that the dataflow has missed out on all input between when that snapshot was taking and resume.&lt;/p&gt;

&lt;p&gt;In this case, your &lt;code&gt;StatefulSource.snapshot&lt;/code&gt; can return &lt;code&gt;None&lt;/code&gt; and no recovery data will be saved. You can then ignore the &lt;code&gt;resume_state&lt;/code&gt; argument of &lt;code&gt;PartitionedInput.build_part&lt;/code&gt; because it will always be &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>connectors</category>
    </item>
    <item>
      <title>How We Detect Anomalies In Our AWS Infrastructure (And Have Peaceful Nights)</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Tue, 02 May 2023 18:50:54 +0000</pubDate>
      <link>https://dev.to/bytewax/how-we-detect-anomalies-in-our-aws-infrastructure-and-have-peaceful-nights-19k1</link>
      <guid>https://dev.to/bytewax/how-we-detect-anomalies-in-our-aws-infrastructure-and-have-peaceful-nights-19k1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mE8HEAOX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d85qqusgtuorj5buicp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mE8HEAOX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d85qqusgtuorj5buicp0.png" alt="Post image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Everyone who's using a cloud provider wants to monitor the system to detect anomalies in the usage. We run some internal data services, our website/blog and a few demo clusters on AWS and we wanted a low-maintenance way to monitor the infrastructure for issues, so we took the opportunity to dogfood Bytewax, of course :).&lt;/p&gt;

&lt;p&gt;In this blog post, we will walk you through the process of building a cloud-based anomaly detection system using Bytewax, Redpanda, and Amazon Web Services (AWS). Our goal is to create a dataflow that detects anomalies in EC2 instance CPU utilization. To achieve this, we will collect usage data from AWS CloudWatch using &lt;a href="https://www.elastic.co/logstash/"&gt;Logstash&lt;/a&gt; and store it using &lt;a href="https://redpanda.com/"&gt;Redpanda&lt;/a&gt;, a Kafka-compatible streaming data platform. Finally, we will use Bytewax, a Python stream processor, to build our anomaly detection system.&lt;/p&gt;

&lt;p&gt;This is exactly the same infrastructure we use internally at Bytewax and, in fact, we haven't touched it for months!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Required Infrastructure on AWS
&lt;/h2&gt;

&lt;p&gt;Before we begin, ensure that you have the following prerequisites set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS CLI configured with admin access&lt;/li&gt;
&lt;li&gt;Helm&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;A Kubernetes cluster running in AWS and kubectl configured to access it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configuring Kubernetes and Redpanda
&lt;/h3&gt;

&lt;p&gt;In this section, we will configure Kubernetes and Redpanda using the provided code snippets. Make sure you have a running Kubernetes cluster in AWS and kubectl configured to access it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Set up a namespace
&lt;/h3&gt;

&lt;p&gt;Create a new namespace for Redpanda and set it as the active context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create ns redpanda-bytewax


kubectl config set-context --current --namespace=redpanda-bytewax

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Install Cert-Manager and Redpanda Operator
&lt;/h3&gt;

&lt;p&gt;The Redpanda operator requires cert-manager to create certificates for TLS communication. To install cert-manager with Helm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo add jetstack https://charts.jetstack.io &amp;amp;amp;&amp;amp;amp; \
helm repo update &amp;amp;amp;&amp;amp;amp; \
helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.4.4 \
  --set installCRDs=true

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fetch the latest Redpanda Operator version, add the Redpanda Helm repo, and install the Redpanda Operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export VERSION=$(curl -s https://api.github.com/repos/redpanda-data/redpanda/releases/latest | jq -r .tag_name)


helm repo add redpanda https://charts.vectorized.io/ &amp;amp;amp;&amp;amp;amp; helm repo update


kubectl apply -k https://github.com/redpanda-data/redpanda/src/go/k8s/config/crd?ref=$VERSION


helm install redpanda-operator redpanda/redpanda-operator --namespace redpanda-system --create-namespace --version $VERSION

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create Redpanda cluster
&lt;/h3&gt;

&lt;p&gt;Save the following YAML configuration in a file named &lt;code&gt;3_node_cluster.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: redpanda.vectorized.io/v1alpha1
kind: Cluster
metadata:
  name: three-node-cluster
spec:
  image: &amp;amp;quot;vectorized/redpanda&amp;amp;quot;
  version: &amp;amp;quot;latest&amp;amp;quot;
  replicas: 3
  resources:
    requests:
      cpu: 1
      memory: 1.2Gi
    limits:
      cpu: 1
      memory: 1.2Gi
  configuration:
    rpcServer:
      port: 33145
    kafkaApi:
    - port: 9092
    pandaproxyApi:
    - port: 8082
    schemaRegistry:
      port: 8081
    adminApi:
    - port: 9644
    developerMode: true

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the Redpanda cluster configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f ./3_node_cluster.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the status of Redpanda pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get po -lapp.kubernetes.io/component=redpanda

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Export the broker addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export BROKERS=`kubectl get clusters three-node-cluster -o=jsonpath=&amp;amp;apos;{.status.nodes.internal}&amp;amp;apos; | jq -r &amp;amp;apos;join(&amp;amp;quot;,&amp;amp;quot;)&amp;amp;apos;`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Set up topics
&lt;/h3&gt;

&lt;p&gt;Run an rpk container to create and manage topics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl run rpk-shell --rm -i --tty --image vectorized/redpanda --command /bin/bash

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the rpk terminal, export the broker addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export BROKERS=three-node-cluster-0.three-node-cluster.redpanda-bytewax.svc.cluster.local.,three-node-cluster-1.three-node-cluster.redpanda-bytewax.svc.cluster.local.,three-node-cluster-2.three-node-cluster.redpanda-bytewax.svc.cluster.local.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View the cluster information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpk --brokers $BROKERS cluster info

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create two topics with 5 partitions each:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpk --brokers $BROKERS topic create ec2_metrics -p 5


rpk --brokers $BROKERS topic create ec2_metrics_anomalies -p 5

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List the topics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpk --brokers $BROKERS topic list

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consume messages from the &lt;code&gt;ec2_metrics&lt;/code&gt; topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpk --brokers $BROKERS topic consume ec2_metrics -o start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Exporting CloudWatch EC2 Metrics to our Redpanda Cluster with Logstash
&lt;/h2&gt;

&lt;p&gt;Logstash is an open-source data processing pipeline that can ingest data from multiple sources, transform it, and send it to various destinations, such as Redpanda. In this case, we'll use Logstash to collect EC2 metrics from CloudWatch and send them to our Redpanda cluster for further processing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Logstash Permissions
&lt;/h4&gt;

&lt;p&gt;First, we need to create an AWS policy and user with the required permissions for Logstash to access CloudWatch and EC2. Save the following JSON configuration in a file named &lt;code&gt;cloudwatch-logstash-policy.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    &amp;amp;quot;Version&amp;amp;quot;: &amp;amp;quot;2012-10-17&amp;amp;quot;,
    &amp;amp;quot;Statement&amp;amp;quot;: [
        {
            &amp;amp;quot;Sid&amp;amp;quot;: &amp;amp;quot;Stmt1444715676000&amp;amp;quot;,
            &amp;amp;quot;Effect&amp;amp;quot;: &amp;amp;quot;Allow&amp;amp;quot;,
            &amp;amp;quot;Action&amp;amp;quot;: [
                &amp;amp;quot;cloudwatch:GetMetricStatistics&amp;amp;quot;,
                &amp;amp;quot;cloudwatch:ListMetrics&amp;amp;quot;
            ],
            &amp;amp;quot;Resource&amp;amp;quot;: &amp;amp;quot;*&amp;amp;quot;
        },
        {
            &amp;amp;quot;Sid&amp;amp;quot;: &amp;amp;quot;Stmt1444716576170&amp;amp;quot;,
            &amp;amp;quot;Effect&amp;amp;quot;: &amp;amp;quot;Allow&amp;amp;quot;,
            &amp;amp;quot;Action&amp;amp;quot;: [
                &amp;amp;quot;ec2:DescribeInstances&amp;amp;quot;
            ],
            &amp;amp;quot;Resource&amp;amp;quot;: &amp;amp;quot;*&amp;amp;quot;
        }
    ]
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can create the policy and user, and attach the policy to the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam create-policy --policy-name CloudwatchLogstash --policy-document file://cloudwatch-logstash-policy.json
aws iam create-user --user-name logstash-user


export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query &amp;amp;quot;Account&amp;amp;quot; --output text)


aws iam attach-user-policy --policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/CloudwatchLogstash --user-name logstash-user

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To provide access, we can create Kubernetes secrets for the AWS access key and secret access key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create secret generic aws-secret-access-key --from-literal=value=$(aws iam create-access-key --user-name logstash-user | jq -r .AccessKey.SecretAccessKey)


kubectl create secret generic aws-access-key-id --from-literal=value=$(aws iam list-access-keys --user-name logstash-user --query &amp;amp;quot;AccessKeyMetadata[0].AccessKeyId&amp;amp;quot; --output text)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can create an Amazon Elastic Container Registry (ECR) repository to store the custom Logstash image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws ecr create-repository --repository-name redpanda-bytewax


export REPOSITORY_URI=$(aws ecr describe-repositories --repository-names redpanda-bytewax --profile sso-admin --output text --query &amp;amp;quot;repositories[0].repositoryUri&amp;amp;quot;)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a Logstash Image with CloudWatch Input Plugin installed by creating a Dockerfile named &lt;code&gt;logstash-Dockerfile&lt;/code&gt; that has the plugin installed as a &lt;code&gt;RUN&lt;/code&gt; step in the Dockerfile like shown in the dockerfile code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM docker.elastic.co/logstash/logstash:7.17.3
RUN bin/logstash-plugin install logstash-input-cloudwatch

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we build and push the Logstash image to the ECR repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -f logstash-Dockerfile -t $REPOSITORY_URI:\logstash-cloudwatch .


export AWS_REGION=us-west-2


aws ecr get-login-password --region $AWS_REGION --profile sso-admin | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com


docker push $REPOSITORY_URI:\logstash-cloudwatch

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy Logstash on Kubernetes
&lt;/h2&gt;

&lt;p&gt;Now that we have our custom Logstash image, we will deploy it on Kubernetes using the Helm chart provided by Elastic. First, we need to gather some information and create a logstash-values.yaml file with the necessary configuration.&lt;/p&gt;

&lt;p&gt;Run the following commands to obtain the required information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $REPOSITORY_URI


echo $AWS_REGION


echo $BROKERS | sed -e &amp;amp;apos;s/local\./local\:9092/g&amp;amp;apos;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a logstash-values.yaml file and replace the placeholders (shown with &lt;code&gt;&amp;amp;lt;&amp;amp;gt;&lt;/code&gt;) with the information obtained above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image: &amp;amp;quot;&amp;amp;lt;YOUR REPOSITORY URI&amp;amp;gt;&amp;amp;quot;
imageTag: &amp;amp;quot;logstash-cloudwatch&amp;amp;quot;
imagePullPolicy: &amp;amp;quot;Always&amp;amp;quot;

persistence:
  enabled: true

logstashConfig:
  logstash.yml: |
    http.host: 0.0.0.0
    xpack.monitoring.enabled: false

logstashPipeline:
  uptime.conf: |
    input {
      cloudwatch {
        namespace =&amp;amp;gt; &amp;amp;quot;AWS/EC2&amp;amp;quot;
        metrics =&amp;amp;gt; [&amp;amp;quot;CPUUtilization&amp;amp;quot;]
        region =&amp;amp;gt; &amp;amp;quot;&amp;amp;lt;YOUR AWS REGION&amp;amp;gt;&amp;amp;quot;
        interval =&amp;amp;gt; 300
        period =&amp;amp;gt; 300
      }       
    }
    filter {
      mutate {
        add_field =&amp;amp;gt; {
          &amp;amp;quot;[index]&amp;amp;quot; =&amp;amp;gt; &amp;amp;quot;0&amp;amp;quot;
          &amp;amp;quot;[value]&amp;amp;quot; =&amp;amp;gt; &amp;amp;quot;%{maximum}&amp;amp;quot;
          &amp;amp;quot;[instance]&amp;amp;quot; =&amp;amp;gt; &amp;amp;quot;%{InstanceId}&amp;amp;quot;                      
        }
      }
    }
    output {
        kafka {
          bootstrap_servers =&amp;amp;gt; &amp;amp;quot;&amp;amp;lt;YOUR REDPANDA BROKERS&amp;amp;gt;&amp;amp;quot;
          topic_id =&amp;amp;gt; &amp;amp;apos;EC2Metrics&amp;amp;apos;
          codec =&amp;amp;gt; json
        }
    }

extraEnvs:
  - name: &amp;amp;apos;AWS_ACCESS_KEY_ID&amp;amp;apos;
    valueFrom:
      secretKeyRef:
        name: aws-access-key-id
        key: value
  - name: &amp;amp;apos;AWS_SECRET_ACCESS_KEY&amp;amp;apos;
    valueFrom:
      secretKeyRef:
        name: aws-secret-access-key
        key: value

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the logstash-values.yaml file ready, install the Logstash Helm chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm upgrade --install logstash elastic/logstash -f logstash-values.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to verify that Logstash is exporting the EC2 metrics to the Redpanda cluster, open a terminal with rpk and consume the ec2_metrics topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpk --brokers $BROKERS topic consume ec2_metrics -o start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;CTRL-C&lt;/code&gt; to quit the rpk terminal when you're done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Dataflow to Detect Anomalies with Bytewax
&lt;/h2&gt;

&lt;p&gt;With our infrastructure in place, it's time to build a dataflow to detect anomalies. We will use Bytewax and &lt;a href="https://www.bytewax.io/docs/deployment/waxctl"&gt;Waxctl&lt;/a&gt; to define and deploy a dataflow that processes the EC2 instance CPU utilization data stored in the Redpanda cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anomaly Detection with Half Space Trees
&lt;/h3&gt;

&lt;p&gt;Half Space Trees (HST) is an unsupervised machine learning algorithm used for detecting anomalies in streaming data. The algorithm is designed to efficiently handle high-dimensional and high-velocity data streams. HST builds a set of binary trees to partition the feature space into half spaces, where each tree captures a different view of the data. By observing the frequency of points falling into each half space, the algorithm can identify regions that are less dense than others, suggesting that data points within those regions are potential anomalies.&lt;/p&gt;

&lt;p&gt;In our case, we will use HST to detect anomalous CPU usage in EC2 metrics. We'll leverage the Python library River, which provides an implementation of the HST algorithm, and Bytewax, a platform for creating data processing pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Dataflow for Anomaly Detection
&lt;/h3&gt;

&lt;p&gt;To create our dataflow, we'll first import the necessary libraries and set up Kafka connections. The following code snippet demonstrates how to create a dataflow with River and Bytewax to consume EC2 metrics from Kafka and detect anomalous CPU usage using HST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json
import os
import datetime as dt
from pathlib import Path

from bytewax.connectors.kafka import KafkaInput, KafkaOutput
from bytewax.dataflow import Dataflow
from bytewax.recovery import SqliteRecoveryConfig

from river import anomaly

kafka_servers = os.getenv(&amp;amp;quot;BYTEWAX_KAFKA_SERVER&amp;amp;quot;, &amp;amp;quot;localhost:9092&amp;amp;quot;)
kafka_topic = os.getenv(&amp;amp;quot;BYTEWAX_KAFKA_TOPIC&amp;amp;quot;, &amp;amp;quot;ec2_metrics&amp;amp;quot;)
kafka_output_topic = os.getenv(&amp;amp;quot;BYTEWAX_KAFKA_OUTPUT_TOPIC&amp;amp;quot;, &amp;amp;quot;ec2_metrics_anomalies&amp;amp;quot;)

# Define the dataflow object and kafka input.
flow = Dataflow()
flow.input(&amp;amp;quot;inp&amp;amp;quot;, KafkaInput(kafka_servers.split(&amp;amp;quot;,&amp;amp;quot;), [kafka_topic]))

# convert to percentages and group by instance id
def group_instance_and_normalize(key__data):
  _, data = key__data
  data = json.loads(data)
  data[&amp;amp;quot;value&amp;amp;quot;] = float(data[&amp;amp;quot;value&amp;amp;quot;]) / 100
  return data[&amp;amp;quot;instance&amp;amp;quot;], data

flow.map(group_instance_and_normalize)
# (&amp;amp;quot;c6585a&amp;amp;quot;, {&amp;amp;quot;index&amp;amp;quot;: &amp;amp;quot;1&amp;amp;quot;, &amp;amp;quot;value&amp;amp;quot;: &amp;amp;quot;0.11&amp;amp;quot;, &amp;amp;quot;instance&amp;amp;quot;: &amp;amp;quot;c6585a&amp;amp;quot;})

# Stateful operator for anomaly detection
class AnomalyDetector(anomaly.HalfSpaceTrees):

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our anomaly detector inherits from the HalfSpaceTrees object from the river package and has the following inputs&lt;/p&gt;

&lt;p&gt;n_trees – defaults to 10 height – defaults to 8 window_size – defaults to 250 limits (Dict[Hashable, Tuple[float, float]]) – defaults to None seed (int) – defaults to None&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  def __init__ (self, *args, **kwargs):
      super(). __init__ (*args, n_trees=5, height=3, window_size=5, seed=42, **kwargs)

  def update(self, data):
      self.learn_one({&amp;amp;quot;value&amp;amp;quot;: data[&amp;amp;quot;value&amp;amp;quot;]})
      data[&amp;amp;quot;score&amp;amp;quot;] = self.score_one({&amp;amp;quot;value&amp;amp;quot;: data[&amp;amp;quot;value&amp;amp;quot;]})
      if data[&amp;amp;quot;score&amp;amp;quot;] &amp;amp;gt; 0.7:
          data[&amp;amp;quot;anom&amp;amp;quot;] = 1
      else:
          data[&amp;amp;quot;anom&amp;amp;quot;] = 0
      return self, (
          data[&amp;amp;quot;index&amp;amp;quot;],
          data[&amp;amp;quot;timestamp&amp;amp;quot;],
          data[&amp;amp;quot;value&amp;amp;quot;],
          data[&amp;amp;quot;score&amp;amp;quot;],
          data[&amp;amp;quot;anom&amp;amp;quot;],
      )

flow.stateful_map(&amp;amp;quot;detector&amp;amp;quot;, lambda: AnomalyDetector(), AnomalyDetector.update)
# ((&amp;amp;quot;c6585a&amp;amp;quot;, {&amp;amp;quot;index&amp;amp;quot;: &amp;amp;quot;1&amp;amp;quot;, &amp;amp;quot;value&amp;amp;quot;:0.08, &amp;amp;quot;instance&amp;amp;quot;: &amp;amp;quot;fe7f93&amp;amp;quot;, &amp;amp;quot;score&amp;amp;quot;:0.02}))

# filter out non-anomalous values
flow.filter(lambda x: bool(x[1][4]))

flow.map(lambda x: (x[0], json.dumps(x[1][4])))
flow.output(&amp;amp;quot;output&amp;amp;quot;, KafkaOutput([kafka_servers], kafka_output_topic))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this dataflow, we first read data from Kafka and deserialize the JSON message. We then normalize the CPU usage values and group them by the instance ID. Next, we apply the AnomalyDetector class inside a stateful operator, which calculates the anomaly score for each data point using HST. We set a threshold for the anomaly score (0.7 in this example) and mark data points as anomalous if their scores exceed the threshold. Finally, we filter out non-anomalous values and output the anomalous data points to a separate Kafka topic.&lt;/p&gt;

&lt;p&gt;Using this dataflow, we can continuously monitor EC2 metrics and detect anomalous CPU usage, helping us identify potential issues in our infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Dataflow docker image
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;dataflow-Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM bytewax/bytewax:0.16.0-python3.9
RUN /venv/bin/pip install river==0.10.1 pandas confluent-kafka


docker build -f dataflow-Dockerfile -t $REPOSITORY_URI:\dataflow . 


docker push $REPOSITORY_URI:\dataflow

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploying the Dataflow
&lt;/h2&gt;

&lt;p&gt;To deploy the dataflow, we'll use the Bytewax command-line tool, waxctl. There are two options for deploying the dataflow, depending on how you have set up your Kafka server environment variable. When we deploy our dataflow we will set the processes (denoted by &lt;code&gt;p&lt;/code&gt;) to 5 to match the number of partitions we set when we intially created our redpanda topic.&lt;/p&gt;

&lt;h4&gt;
  
  
  Option 1: Generate waxctl command
&lt;/h4&gt;

&lt;p&gt;Use the following command to generate the waxctl command with the appropriate environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo&amp;amp;quot;
waxctl df deploy ./dataflow.py \\
  --name ec2-cpu-ad \\
  -p 5 \\
  -i $REPOSITORY_URI \\
  -t dataflow \\
  -e &amp;amp;apos;\&amp;amp;quot;BYTEWAX_KAFKA_SERVER=$BROKERS\&amp;amp;quot;&amp;amp;apos; \\
  -e BYTEWAX_KAFKA_TOPIC_GROUP_ID=dataflow_group \\
  --debug
&amp;amp;quot;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output the waxctl command with the correct Kafka server values. Copy the output and run it to deploy the dataflow.&lt;/p&gt;

&lt;h4&gt;
  
  
  Option 2: Hardcoded BYTEWAX_KAFKA_SERVER value
&lt;/h4&gt;

&lt;p&gt;If you prefer to hardcode the Kafka server values, use the following command to deploy the dataflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;waxctl df deploy ./dataflow.py \
  --name ec2-cpu-ad \
  -p 5 \
  -i $REPOSITORY_URL \
  -t dataflow \
  -e &amp;amp;apos;&amp;amp;quot;BYTEWAX_KAFKA_SERVER=three-node-cluster-0.three-node-cluster.redpanda-bytewax.svc.cluster.local.,three-node-cluster-1.three-node-cluster.redpanda-bytewax.svc.cluster.local.,three-node-cluster-2.three-node-cluster.redpanda-bytewax.svc.cluster.local.&amp;amp;quot;&amp;amp;apos; \
  -e BYTEWAX_KAFKA_TOPIC_GROUP_ID=dataflow_group \
  --debug

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have deployed our dataflow, after enough time, you'll be able to consume from the anomalies topic to see any anomalies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpk --brokers $BROKERS topic consume ec2_metrics_anomalies -o start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a next step, you could deploy a dataflow to consume from the anomalies and alert you in Slack! Or add &lt;a href="https://github.com/rerun-io/rerun"&gt;rerun&lt;/a&gt; like we demonstrated in the previous blog post to visualize the anomalies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, we have demonstrated how to set up a system for monitoring EC2 metrics and detecting anomalous CPU usage. By leveraging tools like Logstash, &lt;a href="https://redpanda.com/"&gt;Redpanda&lt;/a&gt;, &lt;a href="https://riverml.xyz/0.15.0/"&gt;River&lt;/a&gt;, and Bytewax, we've created a robust and scalable pipeline for processing and analyzing streaming data.&lt;/p&gt;

&lt;p&gt;This system provides a range of benefits, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Efficiently processing high-dimensional and high-velocity data streams&lt;/li&gt;
&lt;li&gt;Using the Half Space Trees unsupervised machine learning algorithm for detecting anomalies in streaming data&lt;/li&gt;
&lt;li&gt;Continuously monitoring EC2 metrics and identifying potential issues in the infrastructure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this setup, you can effectively monitor your EC2 instances and ensure that your infrastructure is running smoothly, helping you proactively address any issues that may arise.&lt;/p&gt;

&lt;p&gt;That's it! You now have a working cloud-based anomaly detection system using &lt;a href="https://bytewax.io/"&gt;Bytewax&lt;/a&gt;, &lt;a href="https://redpanda.com/"&gt;Redpanda&lt;/a&gt;, and AWS. Feel free to adapt this setup to your specific use case and explore the various features and capabilities offered by these tools.&lt;/p&gt;

</description>
      <category>anomalydetection</category>
      <category>aws</category>
      <category>redpanda</category>
    </item>
    <item>
      <title>Data Council: The Highlights of Day 2</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Sun, 26 Mar 2023 00:45:10 +0000</pubDate>
      <link>https://dev.to/bytewax/data-council-the-highlights-of-day-2-183e</link>
      <guid>https://dev.to/bytewax/data-council-the-highlights-of-day-2-183e</guid>
      <description>&lt;p&gt;Welcome back, data enthusiasts! I'm excited to dive into the second installment of my blog series covering the extraordinary Data Council Conference. If you haven't already, be sure to check out &lt;a href="https://dev.to/bytewax/data-council-the-highlights-of-day-1-493h"&gt;my first post&lt;/a&gt;, which provided a comprehensive overview of the engaging talks and workshops from Day 1.&lt;/p&gt;

&lt;p&gt;On Day 2, before sessions, we are organizing an informal #StreamBrew coffee gathering for early birds at 7:15 am at KesosTacos near the conference venue. RSVP &lt;a href="https://bitly.com/m/bytewax"&gt;here&lt;/a&gt;. I hope to mingle, network, and enjoy some scrumptious breakfast migas alongside morning coffee. If you've never had migas, don't worry - I haven't either - you won't experiment alone! &lt;/p&gt;

&lt;h2&gt;
  
  
  Panels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AI Panel
&lt;/h3&gt;

&lt;p&gt;One of the most highly anticipated events on Day 2 of the Data Council Conference is the AI Panel. Though details about the panel's specific focus remain under wraps, the excitement is palpable. I expect a riveting discussion featuring top-tier experts, who will undoubtedly share their unique perspectives on artificial intelligence's current state and future directions. AI changes the world we are living in; it happens almost every week, every month, for sure!&lt;/p&gt;

&lt;h3&gt;
  
  
  How Investors Think About Data
&lt;/h3&gt;

&lt;p&gt;Another must-attend event on Day 2 is the panel titled "How Investors Think About Data," featuring an impressive lineup of investment professionals. Gain valuable insights from Lauren Reeder, Partner at Sequoia Capital; Slater Stich, Partner at Bain Capital Ventures; Leigh Marie Braswell, Principal at Founders Fund; and Pete Soderling, Founder of Data Community Fund.&lt;/p&gt;

&lt;p&gt;I work for a data-oriented startup. And given the current state of the economy, including the infamous SVB disaster, I am curious about what fundraising will look like in the mid-long term and how to maximize our chances to succeed. Also, Pete is the founder and chair of the Data Council conference, and I am eager to hear from him too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Talks
&lt;/h2&gt;

&lt;p&gt;Day 2 of the Data Council Conference offers three tracks, full schedule is &lt;a href="https://docs.google.com/document/d/1T3dtBXeEyrujeg-5H8L5ncWKGuq3vMFYMyjriXWMAAI/edit"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first track, "Applied &amp;amp; Generative AI," covers topics such as Large Language/Transformer Models, generative AI, product-based implementations of new research methods, and exciting new features powered by machine learning inside products.&lt;/p&gt;

&lt;p&gt;The second track, "Analytics," focuses on the latest tools, techniques, and best practices for extracting valuable insights from data. You'll learn how top teams are solving their analytics challenges and discover the best new tools in the process.&lt;/p&gt;

&lt;p&gt;Finally, my favorite one, the "Data Culture &amp;amp; Community" track. It emphasizes fostering a vibrant data ecosystem and promoting collaboration among data professionals. Sessions in this track will highlight the role of community building, open-source projects, and knowledge sharing in advancing data science and data engineering. &lt;/p&gt;

&lt;p&gt;In case you're torn between multiple sessions like me, remember that many of the presentations will be recorded and made available for viewing later. With that in mind, I will highlight only a fraction of what sparks my interest.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/generative-ai-for-product-builders?hsLang=en"&gt;Tristan Zajonc - Generative AI for Product Builders &lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I always considered no-code or low-code solutions an excellent option for a non-technical (and technical, too, in some cases) founder to build a prototype and get their MVP out there as soon as possible without hiring a bunch of developers. DALL•E, MidJourney, and Stable Diffusion did a similar thing and unlocked creativity for the rest of us. In that light, Tristan's talk about the caveats and nuances of building products using generative AI is very well-timed and relevant. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/how-vercel-builds-dozens-of-metrics-from-one-heterogenous-table?hsLang=en"&gt;Thomas Mickley-Doyle "How Vercel Builds Dozens of Metrics from One Heterogenous Table"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I remember quite a few blog posts about the importance of reacting quickly to changes. Partly because Bytewax is enabling real-time ML and because it's a hot topic. Thomas Mickley-Doyle from Vercel will also share their innovative approach to data-driven decision-making. Vercel's strategy has increased stakeholder participation in analytics, reduced troubleshooting time for outlier events, and eliminated the data team as a bottleneck for data-related tasks. Sounds like a lot of fun!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/behind-the-curtain-what-it-takes-to-support-the-worlds-most-popular-open-source-communities?hsLang=en"&gt;Katrina Riehl "Behind the Curtain: What it Takes to Support the World's Most Popular Open Source Communities"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Dr. Katrina Riehl is President of the Board of Directors at NumFOCUS, Head of the Streamlit Data Team at Snowflake, and Adjunct Lecturer at Georgetown University. If you are building an OOS-driven business or care about how the community perceives your brand (and you better do :)), her talk is a must-go. NumFOCUS is operating on a vast scale: 50 sponsored projects and 60 affiliated projects, including some of the world's most popular open-source projects like NumPy, Scipy, Jupyter, and Pandas. There is definitely a ton to learn from NumFOCUS and Katrina.&lt;/p&gt;

&lt;p&gt;I can't wait to share more of the content from the conference itself! I expect no less than an unforgettable experience!&lt;/p&gt;

</description>
      <category>conference</category>
      <category>realtimeanalytics</category>
      <category>datascience</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Data Council: The Highlights of Day 1</title>
      <dc:creator>Oli Makhasoeva</dc:creator>
      <pubDate>Thu, 23 Mar 2023 05:44:54 +0000</pubDate>
      <link>https://dev.to/bytewax/data-council-the-highlights-of-day-1-493h</link>
      <guid>https://dev.to/bytewax/data-council-the-highlights-of-day-1-493h</guid>
      <description>&lt;p&gt;The COVID-19 pandemic has profoundly impacted how we work and learn, and the conference industry is no exception. Many events have moved to virtual formats, allowing attendees to participate from the comfort of their own homes. I even built a business around it! And while I absolutely love virtual events and can talk about their advantages endlessly, there's an undeniable charm to in-person conferences, too.&lt;/p&gt;

&lt;p&gt;After *&lt;em&gt;three years *&lt;/em&gt; of remote work, I am thrilled to finally attend &lt;a href="https://www.datacouncil.ai/"&gt;the Data Council conference&lt;/a&gt; in person in Austin and connect with fellow tech enthusiasts face-to-face as soon as next week!&lt;/p&gt;

&lt;p&gt;The conference attracts diverse data professionals from various industries, and whilst I've been at events that featured data talks or data tracks and even organized a virtual data-focused conference myself, it's the first time when I have a chance to see so many professionals interested in the latest developments in data engineering, data science, machine learning, and AI.&lt;/p&gt;

&lt;p&gt;Come say hi 👋 I'm also bringing &lt;a href="https://bytewax.io/"&gt;Bytewax's&lt;/a&gt; swag that you don't want to miss, so &lt;a href="https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-1lhq9bxbr-T3CXxR_9RIUGb4qcBK26Qw"&gt;let's keep in touch!&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today I want to share some of the sessions that I found particularly exciting and would like to attend.&lt;/p&gt;

&lt;p&gt;I have to split this post because it's too much to cover in one shot; you are reading about Day 1, March 28th.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://docs.google.com/document/d/1T3dtBXeEyrujeg-5H8L5ncWKGuq3vMFYMyjriXWMAAI/edit"&gt;Agenda&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The conference features an action-packed schedule across three days, including regular and lightning talks, workshops, and even speaker office hours.  The latter is especially helpful for newcomers to the community (like me), facilitating connections with experts.&lt;/p&gt;

&lt;p&gt;Beyond the formal sessions, the conference also offers plenty of opportunities for informal networking (see &lt;a href="https://twitter.com/DataCouncilAI/status/1630994017679802371?s=20"&gt;this thread&lt;/a&gt;). We (Bytewax) are organizing &lt;a href="https://bit.ly/3YszNvd?r=lp"&gt;#StreamBrew coffee&lt;/a&gt; on March 29th in the morning (7:15 AM) and &lt;a href="https://bit.ly/3ZGzRsw?r=lp"&gt;#StreamBrew Beer&lt;/a&gt; in the evening on March 30th.&lt;/p&gt;

&lt;p&gt;No wonder that with so much to offer this conference is a must-attend event for data folks!&lt;/p&gt;

&lt;h2&gt;
  
  
  Keynotes
&lt;/h2&gt;

&lt;p&gt;As I said before, the conference's schedule is crowded, and keynotes are no exception. 2 on each day!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/building-a-control-plane-for-data?hsLang=en"&gt;Shirshanka Das "Building a Control Plane for Data"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The conference kicks off with an exciting keynote by &lt;a href="https://www.linkedin.com/in/shirshankadas/"&gt;Shirshanka Das&lt;/a&gt;. Shirshanka is a co-founder and CEO of Acryl Data. He will discuss the control plane for data, a harmonizing layer powered by metadata that unifies data discovery, observability, quality, governance, and management. He will describe the fundamental characteristics of a control plane and explain the use cases that can be accomplished with a unified control plane.&lt;/p&gt;

&lt;p&gt;I am obsessed with unification and simplification. It brings order and enables teams to work more effectively. Thrilled to hear Shirshanka's thoughts on how to do that for data stacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/big-data-is-dead?hsLang=en"&gt;Jordan Tigani "Big Data is Dead" &lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Next up is &lt;a href="https://twitter.com/jrdntgn"&gt;Jordan Tigani&lt;/a&gt; of MotherDuck with an intriguing title, "Big Data is Dead." The conference's website didn't have a description of the talk at the time I was writing this, but I googled and found &lt;a href="https://motherduck.com/blog/big-data-is-dead/"&gt;a fresh blog post&lt;/a&gt; by Jordan. &lt;br&gt;
I have to admit, I was a little skeptical about the title as it sounds like clickbait (unrelated, but I have a background in Scala, and Scala is dead forever and dies every year again and again, so it's not news). &lt;/p&gt;

&lt;p&gt;Nonetheless, Jordan is exceptionally qualified to talk about this topic, he shares graphs based on query logs, deal post-mortems, benchmark results, customer support tickets, customer conversations, service logs, and published blog posts. He has his points and I won't post spoilers by citing his blog post. Besides, I am sure he has more to share in his keynote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Talks
&lt;/h2&gt;

&lt;p&gt;There are three tracks on the day 1: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Engineering &amp;amp; Infra&lt;/li&gt;
&lt;li&gt;Data Science &amp;amp; Algos&lt;/li&gt;
&lt;li&gt;ML Ops &amp;amp; Platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is challenging to choose what to highlight, and I might overlook or forget some talks, so if your favorite one is not on the list, please feel free to let me know on &lt;a href="https://join.slack.com/t/bytewaxcommunity/shared_invite/zt-1lhq9bxbr-T3CXxR_9RIUGb4qcBK26Qw"&gt;our Slack&lt;/a&gt;, or tag us on &lt;a href="https://twitter.com/bytewax"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/company/bytewax"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/Oli_kitty"&gt;my DMs&lt;/a&gt; are open too.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/data-contracts-accountable-data-quality?hsLang=en"&gt;Chad Sanderson "Data Contracts: Accountable Data Quality."&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/chad-sanderson/"&gt;Chad Sanderson&lt;/a&gt; is the Founder of Data Quality Camp, and &lt;a href="https://join.slack.com/t/dataqualitycamp/shared_invite/zt-1rk5xsx5j-o3dnRa75iM1mY5~R9HWJMg"&gt;the Data Quality Camp's Slack&lt;/a&gt; is the friendliest place to be. The channels are active, members are helpful, and you can even shamelessly promote whatever you want in the #be-shameless :D&lt;/p&gt;

&lt;p&gt;If you're interested in the data contracts, then Chad's talk is definitely worth checking out. He recently &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7044381753561497600/"&gt;posted on his LinkedIn&lt;/a&gt;  that it's going to be the most in-depth presentation yet on how they implemented data contracts at scale at Convoy.&lt;/p&gt;

&lt;p&gt;You also want to attend Data Quality Camp's first-ever in-person happy hour on Monday the 27th at the Stay Put Brewery near the event venue.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/extinguishing-the-garbage-fire-of-ml-testing?hsLang=en"&gt;Emily Curtin "Extinguishing the Garbage Fire of ML Testing"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The abstract of &lt;a href="https://www.linkedin.com/in/emilymaycurtin"&gt;Emily Curtin&lt;/a&gt;'s (Staff MLOps Engineer at Intuit Mailchimp) talk resonates with me, I also think that testing should be at the heart and mind of people implementing complex systems. Emily is focusing on testing in MLOps and Data Science, which I need to familiarize myself with, and I look forward to learning about it from her.&lt;/p&gt;

&lt;p&gt;I also adore that she says in her bio that she gets paid to say "it depends" and "well actually."&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/how-to-interpret-and-explain-your-black-box-models?hsLang=en"&gt;Sophia Yang "How to Interpret &amp;amp; Explain Your Black-Box Models?"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/sophiamyang?trk=public_profile_browsemap"&gt;Sophia Yang&lt;/a&gt; is a Senior Data Scientist and a Developer Advocate at Anaconda. She is highly knowledgeable about technology and passionate about data science and Python open-source communities.&lt;br&gt;
I think we share many interests, so I'm not missing her talk in which she covers popular model explanation techniques such as explainable boosting machine, visual analytics, distillation, prototypes, saliency map, counterfactual, feature visualization, LIME, SHAP, interpretML, and TCAV.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V53xU38b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qot8zk7yk5b0uke5dwbm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V53xU38b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qot8zk7yk5b0uke5dwbm.jpg" alt="Jules Damji at Data Love" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/huggingface-ray-air-integration-a-python-developers-guide-to-scaling-transformers?hsLang=en"&gt;Jules Damji &amp;amp; Antoni Baum "HuggingFace + Ray AIR Integration: A Python Developer's Guide to Scaling Transformers"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Last but not least, I want to highlight a talk by &lt;a href="https://twitter.com/2twitme"&gt;Jules Damji&lt;/a&gt;, who spoke at one of my events before (check out his handmade avatar from the pre Midjourney era). Jules and Antoni will talk about Hugging Face Transformers and Ray AIR. It's cutting-edge Machine Learning, and I'm always willing to discover more about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workshops
&lt;/h2&gt;

&lt;p&gt;At Data Council all workshops are included for free in the cost of your ticket so I will try to attend them too.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/urgent-help-these-pets-find-homes-working-across-teams-in-datahub?hsLang=en"&gt;Maggie Hays &amp;amp; Paul Logan "URGENT! Help these Pets Find Homes: Working Across Teams in DataHub"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/maggie-hays/"&gt;Maggie&lt;/a&gt; and Paul's workshop is about Long Tail Companions (a hypothetical pet adoption service). It is in crisis – its data infrastructure has ground to a halt, and they cannot process any adoptions. I care about pets, love fixing failures, and enjoy teamwork. All things combined, it sounds like an excellent session for me.   &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.datacouncil.ai/talks/how-to-make-marketing-fall-in-love-with-data-modeling?hsLang=en"&gt;Erik Edelmann &amp;amp; Meredith Adler "How to Make Marketing Fall In Love with Data Modeling&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Data Modeling applied to marketing is obviously something that I care about. I'm joining &lt;a href="https://www.linkedin.com/in/erik-edelmann-43247358"&gt;Erik&lt;/a&gt; and Meredith for a demo of the campaign they built at Hightouch. They will cover how the team modeled the data, validated the results, and created a reusable process to support future marketing campaigns.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎈Community party
&lt;/h2&gt;

&lt;p&gt;The day wraps up with a Community Party at 5:30 pm (kudos to Databand for supporting it).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RwyiABu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o17mfpl6gr7x1w5oa2or.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RwyiABu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o17mfpl6gr7x1w5oa2or.png" alt="Zander Matheson - getting real time" width="880" height="880"&gt;&lt;/a&gt;&lt;br&gt;
Don't forget to attend &lt;a href="https://www.datacouncil.ai/talks/getting-real-time-when-to-move-from-batch-to-streaming-and-how-to-do-it-without-hiring-an-entirely-new-team?hsLang=en"&gt;Zander's awesome talk&lt;/a&gt;, I'll be giving away awesome swag there!&lt;/p&gt;

&lt;p&gt;Also see you at #StreamBrew, RSVP &lt;a href="https://bitly.com/m/bytewax"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the next posts I'll cover following days, stay tuned!&lt;br&gt;
See in Austin!&lt;/p&gt;

&lt;p&gt;UPD: &lt;a href="https://dev.to/bytewax/data-council-the-highlights-of-day-2-183e"&gt;Day 2&lt;/a&gt;&lt;/p&gt;

</description>
      <category>conference</category>
      <category>datascience</category>
      <category>dataengineering</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
