3763 lines
182 KiB
HTML
3763 lines
182 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="description" content="Learn to implement chaos engineering using Chaos Toolkit and Chaos Monkey for Java (Spring Boot), Node.js, Kubernetes, and Istio to enhance system resilience.">
|
||
<meta name="keywords" content="Chaos Monkey, Chaos engineering, Kubernetes, spring boot, microservices">
|
||
|
||
<meta property="og:description" content="Learn to implement chaos engineering using Chaos Toolkit and Chaos Monkey for Java (Spring Boot), Node.js, Kubernetes, and Istio to enhance system resilience.">
|
||
<meta property="og:site_name" content="dzone.com">
|
||
<meta property="og:title" content="Chaos Engineering for Microservices">
|
||
<meta property="og:url" content="https://dzone.com/articles/chaos-engineering-for-microservices">
|
||
<meta property="og:image" content="https://dz2cdn1.dzone.com/storage/article-thumb/18334696-thumb.jpg">
|
||
<meta property="og:type" content="article">
|
||
|
||
<meta name="twitter:site" content="@DZoneInc">
|
||
<meta name="twitter:image" content="https://dz2cdn1.dzone.com/storage/article-thumb/18334696-thumb.jpg">
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:description" content="Learn to implement chaos engineering using Chaos Toolkit and Chaos Monkey for Java (Spring Boot), Node.js, Kubernetes, and Istio to enhance system resilience.">
|
||
<meta name="twitter:title" content="Chaos Engineering for Microservices">
|
||
|
||
|
||
|
||
<meta name="referrer" content="origin-when-cross-origin">
|
||
<meta name="google-site-verification" content="kndbhxcupfEqWmZclhCpB6vlgOs7QSmx2UHAGGnP2mA">
|
||
<meta name="df-verify" content="df0d76632b4543">
|
||
|
||
<link rel="icon" type="image/x-icon" href="https://dz2cdn1.dzone.com/themes/dz20/images/favicon.png">
|
||
<link rel="image_src" href="https://dz2cdn1.dzone.com/storage/article-thumb/18334696-thumb.jpg">
|
||
<link rel="canonical" href="https://dzone.com/articles/chaos-engineering-for-microservices">
|
||
|
||
<title>Chaos Engineering for Microservices</title>
|
||
|
||
<link rel="preload" href="https://dz2cdn1.dzone.com/themes/dz20/font/fontello.woff?11773374" as="font" type="font/woff" crossorigin="anonymous">
|
||
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/icons.css">
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/lib/static/bootstrap/bootstrap.min.css">
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/article/global.css">
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/header-updated/styles.css">
|
||
<style>
|
||
:root {
|
||
--xs-size: 2px;
|
||
--sm-size: 5px;
|
||
--md-size: 10px;
|
||
--lg-size: 15px;
|
||
--xl-size: 25px;
|
||
--sm-border-size: 8px;
|
||
--sm-font-size: 13px;
|
||
--sm-plus-font-size: 16px;
|
||
--md-font-size: 18px;
|
||
--lg-font-size: 22px;
|
||
--xl-font-size: 26px;
|
||
}
|
||
|
||
/* Display Quick-Access Classes */
|
||
.display-none { display: none; }
|
||
.display-block { display: block; }
|
||
.display-inline { display: inline; }
|
||
.display-inline-block { display: inline-block; }
|
||
|
||
/* Margin Quick-Access Classes */
|
||
.m-xs { margin: var(--xs-size); }
|
||
.m-sm { margin: var(--sm-size); }
|
||
.m-md { margin: var(--md-size); }
|
||
.m-lg { margin: var(--lg-size); }
|
||
.m-xl { margin: var(--xl-size); }
|
||
|
||
.mt-xs, .my-xs { margin-top: var(--xs-size); }
|
||
.mr-xs, .mx-xs { margin-right: var(--xs-size); }
|
||
.mb-xs, .my-xs { margin-bottom: var(--xs-size); }
|
||
.ml-xs, .mx-xs { margin-left: var(--xs-size); }
|
||
|
||
.mt-sm, .my-sm { margin-top: var(--sm-size); }
|
||
.mr-sm, .mx-sm { margin-right: var(--sm-size); }
|
||
.mb-sm, .my-sm { margin-bottom: var(--sm-size); }
|
||
.ml-sm, .mx-sm { margin-left: var(--sm-size); }
|
||
|
||
.mt-md, .my-md { margin-top: var(--md-size); }
|
||
.mr-md, .mx-md { margin-right: var(--md-size); }
|
||
.mb-md, .my-md { margin-bottom: var(--md-size); }
|
||
.ml-md, .mx-md { margin-left: var(--md-size); }
|
||
|
||
.mt-lg, .my-lg { margin-top: var(--lg-size); }
|
||
.mr-lg, .mx-lg { margin-right: var(--lg-size); }
|
||
.mb-lg, .my-lg { margin-bottom: var(--lg-size); }
|
||
.ml-lg, .mx-lg { margin-left: var(--lg-size); }
|
||
|
||
.mt-xl, .my-xl { margin-top: var(--xl-size); }
|
||
.mr-xl, .mx-xl { margin-right: var(--xl-size); }
|
||
.mb-xl, .my-xl { margin-bottom: var(--xl-size); }
|
||
.ml-xl, .mx-xl { margin-left: var(--xl-size); }
|
||
|
||
.ml-auto, .mx-auto { margin-left: auto; }
|
||
.mr-auto, .mx-auto { margin-right: auto; }
|
||
.mt-auto, .my-auto { margin-top: auto; }
|
||
.mb-auto, .my-auto { margin-bottom: auto; }
|
||
|
||
.my-none, .mt-none { margin-top: 0 !important; }
|
||
.mx-none, .mr-none { margin-right: 0 !important; }
|
||
.my-none, .mb-none { margin-bottom: 0 !important; }
|
||
.mx-none, .ml-none { margin-left: 0 !important; }
|
||
|
||
/* Padding Quick-Access Classes */
|
||
.p-xs { padding: var(--xs-size); }
|
||
.p-sm { padding: var(--sm-size); }
|
||
.p-md { padding: var(--md-size); }
|
||
.p-lg { padding: var(--lg-size); }
|
||
.p-xl { padding: var(--xl-size); }
|
||
|
||
.pt-xs, .py-xs { padding-top: var(--xs-size); }
|
||
.pr-xs, .px-xs { padding-right: var(--xs-size); }
|
||
.pb-xs, .py-xs { padding-bottom: var(--xs-size); }
|
||
.pl-xs, .px-xs { padding-left: var(--xs-size); }
|
||
|
||
.pt-sm, .py-sm { padding-top: var(--sm-size); }
|
||
.pr-sm, .px-sm { padding-right: var(--sm-size); }
|
||
.pb-sm, .py-sm { padding-bottom: var(--sm-size); }
|
||
.pl-sm, .px-sm { padding-left: var(--sm-size); }
|
||
|
||
.pt-md, .py-md { padding-top: var(--md-size); }
|
||
.pr-md, .px-md { padding-right: var(--md-size); }
|
||
.pb-md, .py-md { padding-bottom: var(--md-size); }
|
||
.pl-md, .px-md { padding-left: var(--md-size); }
|
||
|
||
.pt-lg, .py-lg { padding-top: var(--lg-size); }
|
||
.pr-lg, .px-lg { padding-right: var(--lg-size); }
|
||
.pb-lg, .py-lg { padding-bottom: var(--lg-size); }
|
||
.pl-lg, .px-lg { padding-left: var(--lg-size); }
|
||
|
||
.pt-xl, .py-xl { padding-top: var(--xl-size); }
|
||
.pr-xl, .px-xl { padding-right: var(--xl-size); }
|
||
.pb-xl, .py-xl { padding-bottom: var(--xl-size); }
|
||
.pl-xl, .px-xl { padding-left: var(--xl-size); }
|
||
|
||
.py-none, .pt-none { padding-top: 0 !important; }
|
||
.px-none, .pr-none { padding-right: 0 !important; }
|
||
.py-none, .pb-none { padding-bottom: 0 !important; }
|
||
.px-none, .pl-none { padding-left: 0 !important; }
|
||
|
||
/* Flex Quick-Access Classes */
|
||
.flex {
|
||
display: flex;
|
||
}
|
||
|
||
.flex-column {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.flex-column-reverse {
|
||
display: flex;
|
||
flex-direction: column-reverse;
|
||
}
|
||
|
||
.flex-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
}
|
||
|
||
.flex-row-reverse {
|
||
display: flex;
|
||
flex-direction: row-reverse;
|
||
}
|
||
|
||
.flex-wrap {
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.flex-grow {
|
||
flex-grow: 1;
|
||
}
|
||
|
||
.align-center { align-items: center; }
|
||
.align-end { align-items: flex-end; }
|
||
|
||
.content-center {
|
||
align-content: center;
|
||
}
|
||
|
||
.justify-center { justify-content: center; }
|
||
.justify-start { justify-content: flex-start; }
|
||
.justify-end { justify-content: flex-end; }
|
||
.justify-around { justify-content: space-around; }
|
||
.justify-between { justify-content: space-between; }
|
||
.justify-evenly { justify-content: space-evenly; }
|
||
|
||
.gap-sm { gap: var(--sm-size); }
|
||
.gap-md { gap: var(--md-size); }
|
||
.gap-lg { gap: var(--lg-size); }
|
||
.gap-xl { gap: var(--xl-size); }
|
||
|
||
/* Display Quick-Access Classes */
|
||
.inline-block { display: inline-block; }
|
||
|
||
/* Font Quick-Access Classes */
|
||
.font-xl { font-size: var(--xl-font-size); }
|
||
.font-lg { font-size: var(--lg-font-size); }
|
||
.font-md { font-size: var(--md-font-size); }
|
||
.font-sm-plus { font-size: var(--sm-plus-font-size); }
|
||
.font-sm { font-size: var(--sm-font-size); }
|
||
|
||
.font-strike { text-decoration: line-through; }
|
||
.font-underline { text-decoration: underline; }
|
||
.font-overline { text-decoration: overline; }
|
||
|
||
.font-italic { font-style: italic; }
|
||
.font-bold { font-weight: bold; }
|
||
|
||
.font-black { color: #000000; }
|
||
.font-white { color: #ffffff; }
|
||
.font-gray { color: var(--brand-gray-text); }
|
||
.font-danger { color: var(--header-dropdown-button-bg-danger); }
|
||
.font-center { text-align: center; }
|
||
|
||
.no-wrap { white-space: nowrap; }
|
||
|
||
/* Consistent headings between h and non-h tags */
|
||
.heading {
|
||
margin-top: 0;
|
||
margin-bottom: var(--md-size);
|
||
}
|
||
|
||
.heading.font-xl { line-height: var(--xl-font-size); }
|
||
.heading.font-lg { line-height: var(--lg-font-size); }
|
||
.heading.font-md { line-height: var(--md-font-size); }
|
||
.heading.font-sm-plus { line-height: var(--sm-plus-font-size); }
|
||
.heading.font-sm { line-height: var(--sm-font-size); }
|
||
|
||
/* Font Clamp Quick-Access Classes */
|
||
.line-clamp,
|
||
.line-clamp-2,
|
||
.line-clamp-3,
|
||
.line-clamp-4,
|
||
.line-clamp-5 {
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 4;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.line-clamp-2 { -webkit-line-clamp: 2 !important; }
|
||
.line-clamp-3 { -webkit-line-clamp: 3 !important; }
|
||
.line-clamp-4 { -webkit-line-clamp: 4 !important; }
|
||
.line-clamp-5 { -webkit-line-clamp: 5 !important; }
|
||
|
||
/* User-Select Quick-Access Classes */
|
||
.select-none { user-select: none; }
|
||
|
||
/* Position Quick-Access Classes */
|
||
.absolute { position: absolute; }
|
||
.relative { position: relative; }
|
||
.float-left { float: left; }
|
||
.float-right { float: right; }
|
||
|
||
.pos-top { top: 0; }
|
||
.pos-right { right: 0; }
|
||
.pos-bottom { bottom: 0; }
|
||
.pos-left { left: 0; }
|
||
|
||
.va-top { vertical-align: top; }
|
||
.va-middle { vertical-align: middle; }
|
||
.va-bottom { vertical-align: bottom; }
|
||
|
||
/* Transition Quick-Access Classes */
|
||
.trans-linear-quick {
|
||
transition: all 0.15s linear;
|
||
}
|
||
|
||
/* Background Quick-Access Classes */
|
||
.bg-gray { background: #cccccc; }
|
||
.bg-white { background-color: white; }
|
||
.bg-none { background: none; }
|
||
|
||
/* Border Quick-Access Classes */
|
||
.border-gray { border: 1px solid #cccccc; }
|
||
.tab-pane.border-gray { border: 1px solid #ddd; }
|
||
.no-border, .border-none { border: none !important; }
|
||
|
||
.bt-none { border-top: none !important; }
|
||
.br-none { border-right: none !important; }
|
||
.bb-none { border-bottom: none !important; }
|
||
.bl-none { border-left: none !important; }
|
||
|
||
/* Border Radius Quick-Access Classes */
|
||
|
||
.round-t-sm, .round-tl-sm { border-top-left-radius: var(--sm-border-size); }
|
||
.round-t-sm, .round-tr-sm { border-top-right-radius: var(--sm-border-size); }
|
||
.round-b-sm, .round-bl-sm { border-bottom-left-radius: var(--sm-border-size); }
|
||
.round-b-sm, .round-br-sm { border-bottom-right-radius: var(--sm-border-size); }
|
||
.round-sm { border-radius: var(--sm-border-size); }
|
||
.round-fully { border-radius: 50%; }
|
||
|
||
/* Misc Quick-Access Classes */
|
||
.haikei {
|
||
position: relative;
|
||
background-image: url('https://dz2cdn1.dzone.com/themes/dz20/images/polygon-scatter-haikei-shapes.svg');
|
||
background-repeat: no-repeat;
|
||
background-size: cover;
|
||
}
|
||
|
||
.haikei:before {
|
||
content: '';
|
||
position:absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: var(--color-event-background);
|
||
z-index: -1;
|
||
}
|
||
|
||
.margin-auto-center {
|
||
display: block;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
|
||
.flex-auto-center {
|
||
display: flex;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
|
||
.mw-1100 { max-width: 1100px; }
|
||
.mw-1300 { max-width: 1300px; }
|
||
.full-width { width: 100%; }
|
||
|
||
.h-separator {
|
||
background-color: #cccccc;
|
||
height: 1px;
|
||
width: 100%;
|
||
margin: 5px auto;
|
||
}
|
||
|
||
.no-spacing {
|
||
margin: 0 !important;
|
||
padding: 0 !important;
|
||
}
|
||
|
||
.inherit-color { color: inherit; }
|
||
|
||
.inherit-decoration { text-decoration: inherit; }
|
||
|
||
/* Table Quick-Access Classes */
|
||
.table-border-gray tr:not(:last-child) {
|
||
border-bottom: 1px solid #cccccc;
|
||
}
|
||
|
||
table.full-width tr td:last-child {
|
||
width:100%;
|
||
}
|
||
|
||
/* Animation Quick-Access Classes */
|
||
@keyframes anim-spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(359deg); }
|
||
}
|
||
|
||
.anim-spin {
|
||
display: inline-block;
|
||
animation: anim-spin 2s infinite linear;
|
||
}
|
||
|
||
.hov-pointer { cursor: pointer; }
|
||
.hov-brighten:hover { filter: brightness(1.2); }
|
||
.hov-darken:hover { filter: brightness(0.95); }
|
||
.hov-underline:hover { text-decoration: underline; }
|
||
|
||
/* Small tweaks related to components when using these styles */
|
||
.nav-tabs {
|
||
border-bottom: none;
|
||
}
|
||
.tab-content > .flex-column.active,
|
||
.tab-content > .flex-row.active {
|
||
display: flex;
|
||
}
|
||
|
||
/* Alpine components with x-cloak should not be visible by default until conditionals kick in */
|
||
[x-cloak] { display: none !important; }
|
||
</style>
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/alpine-components/modal.css">
|
||
<script defer src="https://dz2cdn1.dzone.com/themes/dz20/lib/alpinejs/3.13.2/cdn.min.js"></script>
|
||
<script>
|
||
document.addEventListener('alpine:init', () => {
|
||
Alpine.store('article', {
|
||
id: null,
|
||
engagement: {
|
||
open: false,
|
||
page: 1,
|
||
users: [],
|
||
additional: true,
|
||
loading: false,
|
||
initializing: false,
|
||
unauthorized: false,
|
||
enqueued: null,
|
||
dequeued: null,
|
||
|
||
reset() {
|
||
this.open = false;
|
||
this.page = 1;
|
||
this.users.splice(0);
|
||
this.additional = true;
|
||
this.loading = false;
|
||
this.initializing = false;
|
||
this.enqueued = null;
|
||
this.dequeued = null;
|
||
},
|
||
|
||
enqueue(user) {
|
||
this.dequeued = null;
|
||
this.enqueued = user;
|
||
},
|
||
|
||
dequeue(user) {
|
||
this.enqueued = null;
|
||
this.dequeued = user;
|
||
},
|
||
|
||
add(user) {
|
||
this.users.push(user);
|
||
this.enqueued = null;
|
||
},
|
||
|
||
remove(user) {
|
||
const index = this.users.findIndex(u => u.id === user.id);
|
||
|
||
if (index !== -1) {
|
||
this.users.splice(index, 1);
|
||
}
|
||
|
||
this.dequeued = null;
|
||
},
|
||
|
||
contains(user) {
|
||
return this.users.filter(u => u.id === user.id).length;
|
||
}
|
||
}
|
||
});
|
||
|
||
Alpine.effect(() => {
|
||
const store = Alpine.store('article');
|
||
if (!store.engagement.additional && store.engagement.enqueued) {
|
||
if (!store.engagement.contains(store.engagement.enqueued)) {
|
||
store.engagement.add(store.engagement.enqueued);
|
||
}
|
||
}
|
||
});
|
||
|
||
Alpine.effect(() => {
|
||
const store = Alpine.store('article');
|
||
if (store.engagement.page && store.engagement.dequeued) {
|
||
store.engagement.remove(store.engagement.dequeued);
|
||
}
|
||
})
|
||
});
|
||
</script></head>
|
||
<body x-data>
|
||
<div class="skybox skybox-closeBtn dz_skybox" data-gpt-slot="skybox" id="div-gpt-ad-1435246566686-99"></div>
|
||
<header id="ftl-header">
|
||
<div class="header-top">
|
||
<div class="header-container">
|
||
<div class="pull-left logo-container">
|
||
<div class="logo">
|
||
<a class="inner" href="/">
|
||
<picture>
|
||
<source srcset="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.webp" type="image/webp">
|
||
<source srcset="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.png" type="image/png">
|
||
<img src="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.png" width="181" height="56" alt="DZone">
|
||
</picture>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pull-right login-and-search">
|
||
<div id="authenticated-block" class="logged-in">
|
||
<div class="welcome-back">Thanks for visiting DZone today,</div>
|
||
<div id="user-header" class="user-info">
|
||
<button class="user-avatar">
|
||
<span id="header-username" class="username"></span>
|
||
<img id="header-avatar" src="" alt="user avatar">
|
||
</button>
|
||
<div id="user-dropdown" class="browse-user-menu">
|
||
<div class="user-content">
|
||
<a id="header-user-plug" href="#" class="user-description"></a>
|
||
<a id="header-user-edit" href="#" class="edit-profile">Edit Profile</a>
|
||
</div>
|
||
<ul class="user-actions">
|
||
<li id="first-user-action">
|
||
<a id="header-dropdown-manage-email" href="#">Manage Email Subscriptions</a>
|
||
</li>
|
||
<li>
|
||
<a href="/articles/how-to-submit-a-post-to-dzone?utm_source=DZone&utm_medium=user_dropdown&utm_campaign=how_to_post">
|
||
How to Post to DZone
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a href="/articles/dzones-article-submission-guidelines">
|
||
Article Submission Guidelines
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
<div class="bottom">
|
||
<a href="/users/logout.html" class="sign-out">Sign Out</a>
|
||
<a id="dropdown-view-profile" href="#" class="view-profile">View Profile</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="post-content">
|
||
<button id="post-button" class="post-content--button">
|
||
<span class="post-class">Post</span>
|
||
<i class="icon-plus"></i>
|
||
</button>
|
||
|
||
<div id="post-menu" class="posting-links">
|
||
<div class="posting-links-menu">
|
||
<ul>
|
||
<li>
|
||
<img src="https://dz2cdn1.dzone.com/themes/dz20/images/dz-postarticle.svg" width="15" height="18" style="width: 15px; height: 18px;">
|
||
<a href="/content/article/post.html">Post an Article</a>
|
||
</li>
|
||
<li>
|
||
<a id="drafts-link" href="#">Manage My Drafts</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="unauthenticated-block">
|
||
<div class="dz-intro">Over 2 million developers have joined DZone.</div>
|
||
<div class="mobile-invisible sign-in-join">
|
||
<a href="/users/login.html">Log In</a>
|
||
<span class="dz-intro-span">/</span>
|
||
<a href="/static/registration.html">Join</a>
|
||
</div>
|
||
<a class="join-icon" href="/users/login.html" aria-label="User">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide svg-user lucide-user-icon lucide-user">
|
||
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path>
|
||
<circle cx="12" cy="7" r="4"></circle>
|
||
</svg>
|
||
</a>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('alpine:init', () => {
|
||
Alpine.data('searchDrawer', () => ({
|
||
open: false,
|
||
query: '',
|
||
minCharsMet: false,
|
||
|
||
toggleVisibility() {
|
||
this.open = !this.open;
|
||
if (this.open) {
|
||
this.$nextTick(() => {
|
||
this.$refs.query.focus();
|
||
});
|
||
}
|
||
},
|
||
|
||
updateSearchValue() {
|
||
if (!this.query || !this.query.length || this.query.length < 3) {
|
||
this.minCharsMet = false;
|
||
return;
|
||
}
|
||
this.minCharsMet = true;
|
||
localStorage.setItem('ls.searchValue', this.query);
|
||
},
|
||
|
||
searchSite() {
|
||
if (this.minCharsMet) {
|
||
window.location = '/search';
|
||
}
|
||
}
|
||
}));
|
||
});
|
||
</script>
|
||
|
||
<div class="headerSearch" x-data="searchDrawer()" x-cloak>
|
||
<button class="btn-search dropdown-toggle" x-on:click="toggleVisibility()" aria-label="Search">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide svg-search lucide-search-icon lucide-search">
|
||
<path d="m21 21-4.34-4.34"></path>
|
||
<circle cx="11" cy="11" r="8"></circle>
|
||
</svg>
|
||
</button>
|
||
<template x-teleport=".header-container">
|
||
<div id="search-drawer" x-show="open" x-on:click.outside="open = false" x-transition>
|
||
<div class="search-input">
|
||
<input type="text"
|
||
placeholder="Search"
|
||
autofocus="autofocus"
|
||
x-model="query"
|
||
x-ref="query"
|
||
x-on:input.change="updateSearchValue()"
|
||
x-on:keyup.enter="searchSite()"
|
||
>
|
||
<button x-on:click="searchSite()" x-bind:disabled="!minCharsMet">
|
||
<span>Search</span>
|
||
</button>
|
||
</div>
|
||
<div class="search-footer">
|
||
Please enter at least three characters to search
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div> </div>
|
||
<div class="header-bottom">
|
||
<div class="header-bottom-container">
|
||
<a class="resource-link" href="/refcardz">Refcards</a>
|
||
<a class="resource-link" href="/trendreports">Trend Reports</a>
|
||
<div class="resource-link link-menu">
|
||
<a href="/events">Events</a>
|
||
<a href="/events/video-library">Video Library</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<nav class="header-menu-bar">
|
||
<div class="header-menu resource-category">
|
||
<a href="/refcardz">Refcards</a>
|
||
</div>
|
||
<div class="header-menu-separator resource-category-separator"></div>
|
||
<div class="header-menu resource-category">
|
||
<a href="/trendreports">Trend Reports</a>
|
||
</div>
|
||
<div class="header-menu-separator resource-category-separator"></div>
|
||
<div class="header-menu resource-category no-bottom-radius" data-click-activation>
|
||
<p class="menu-label">Events</p>
|
||
<div class="header-menu-items">
|
||
<div class="header-menu-columns">
|
||
<a class="header-menu-item" href="/events">View Events</a>
|
||
<a class="header-menu-item" href="/events/video-library">Video Library</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu zone-menu" data-click-activation>
|
||
<p class="menu-label">Zones <i class="icon-down-dir icon-closed"></i><i class="icon-right-dir icon-open"></i></p>
|
||
<div class="header-menu-items">
|
||
<div class="header-menu-columns">
|
||
<div class="header-menu-column-item">
|
||
<a class="header-menu-item" href="/culture-and-methodologies">Culture and Methodologies</a>
|
||
<a class="header-menu-item" href="/agile">Agile</a>
|
||
<a class="header-menu-item" href="/career-development">Career Development</a>
|
||
<a class="header-menu-item" href="/methodologies">Methodologies</a>
|
||
<a class="header-menu-item" href="/team-management">Team Management</a>
|
||
</div>
|
||
<div class="header-menu-column-item">
|
||
<a class="header-menu-item" href="/data-engineering">Data Engineering</a>
|
||
<a class="header-menu-item" href="/ai-ml">AI/ML</a>
|
||
<a class="header-menu-item" href="/big-data">Big Data</a>
|
||
<a class="header-menu-item" href="/data">Data</a>
|
||
<a class="header-menu-item" href="/databases">Databases</a>
|
||
<a class="header-menu-item" href="/iot">IoT</a>
|
||
</div>
|
||
<div class="header-menu-column-item">
|
||
<a class="header-menu-item" href="/software-design-and-architecture">Software Design and Architecture</a>
|
||
<a class="header-menu-item" href="/cloud-architecture">Cloud Architecture</a>
|
||
<a class="header-menu-item" href="/containers">Containers</a>
|
||
<a class="header-menu-item" href="/integration">Integration</a>
|
||
<a class="header-menu-item" href="/microservices">Microservices</a>
|
||
<a class="header-menu-item" href="/performance">Performance</a>
|
||
<a class="header-menu-item" href="/security">Security</a>
|
||
</div>
|
||
<div class="header-menu-column-item">
|
||
<a class="header-menu-item" href="/coding">Coding</a>
|
||
<a class="header-menu-item" href="/frameworks">Frameworks</a>
|
||
<a class="header-menu-item" href="/java">Java</a>
|
||
<a class="header-menu-item" href="/javascript">JavaScript</a>
|
||
<a class="header-menu-item" href="/languages">Languages</a>
|
||
<a class="header-menu-item" href="/tools">Tools</a>
|
||
</div>
|
||
<div class="header-menu-column-item">
|
||
<a class="header-menu-item" href="/testing-deployment-and-maintenance">Testing, Deployment, and Maintenance</a>
|
||
<a class="header-menu-item" href="/deployment">Deployment</a>
|
||
<a class="header-menu-item" href="/devops-and-cicd">DevOps and CI/CD</a>
|
||
<a class="header-menu-item" href="/maintenance">Maintenance</a>
|
||
<a class="header-menu-item" href="/monitoring-and-observability">Monitoring and Observability</a>
|
||
<a class="header-menu-item" href="/testing-tools-and-frameworks">Testing, Tools, and Frameworks</a>
|
||
</div>
|
||
<div class="header-menu-column-item sponsored">
|
||
<a class="header-menu-item" href="javascript:void(0)">Partner Zones</a>
|
||
<a class="header-menu-item" href="/hubs/build-ai-agents-that-are-ready-for-production/">Build AI Agents That Are Ready for Production</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu parent-category" tabindex="1">
|
||
<a href="/culture-and-methodologies">Culture and Methodologies</a>
|
||
<div class="header-menu-items">
|
||
<a class="header-menu-item" href="/agile">Agile</a>
|
||
<a class="header-menu-item" href="/career-development">Career Development</a>
|
||
<a class="header-menu-item" href="/methodologies">Methodologies</a>
|
||
<a class="header-menu-item" href="/team-management">Team Management</a>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu-separator parent-category-separator"></div>
|
||
<div class="header-menu parent-category" tabindex="2">
|
||
<a href="/data-engineering">Data Engineering</a>
|
||
<div class="header-menu-items">
|
||
<a class="header-menu-item" href="/ai-ml">AI/ML</a>
|
||
<a class="header-menu-item" href="/big-data">Big Data</a>
|
||
<a class="header-menu-item" href="/data">Data</a>
|
||
<a class="header-menu-item" href="/databases">Databases</a>
|
||
<a class="header-menu-item" href="/iot">IoT</a>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu-separator parent-category-separator"></div>
|
||
<div class="header-menu parent-category" tabindex="3">
|
||
<a href="/software-design-and-architecture">Software Design and Architecture</a>
|
||
<div class="header-menu-items">
|
||
<a class="header-menu-item" href="/cloud-architecture">Cloud Architecture</a>
|
||
<a class="header-menu-item" href="/containers">Containers</a>
|
||
<a class="header-menu-item" href="/integration">Integration</a>
|
||
<a class="header-menu-item" href="/microservices">Microservices</a>
|
||
<a class="header-menu-item" href="/performance">Performance</a>
|
||
<a class="header-menu-item" href="/security">Security</a>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu-separator parent-category-separator"></div>
|
||
<div class="header-menu parent-category" tabindex="4">
|
||
<a href="/coding">Coding</a>
|
||
<div class="header-menu-items">
|
||
<a class="header-menu-item" href="/frameworks">Frameworks</a>
|
||
<a class="header-menu-item" href="/java">Java</a>
|
||
<a class="header-menu-item" href="/javascript">JavaScript</a>
|
||
<a class="header-menu-item" href="/languages">Languages</a>
|
||
<a class="header-menu-item" href="/tools">Tools</a>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu-separator parent-category-separator"></div>
|
||
<div class="header-menu parent-category" tabindex="5">
|
||
<a href="/testing-deployment-and-maintenance">Testing, Deployment, and Maintenance</a>
|
||
<div class="header-menu-items">
|
||
<a class="header-menu-item" href="/deployment">Deployment</a>
|
||
<a class="header-menu-item" href="/devops-and-cicd">DevOps and CI/CD</a>
|
||
<a class="header-menu-item" href="/maintenance">Maintenance</a>
|
||
<a class="header-menu-item" href="/monitoring-and-observability">Monitoring and Observability</a>
|
||
<a class="header-menu-item" href="/testing-tools-and-frameworks">Testing, Tools, and Frameworks</a>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu-separator parent-category-separator"></div>
|
||
<div class="header-menu parent-category sponsored" tabindex="6">
|
||
<a href="javascript:void(0)">Partner Zones</a>
|
||
<div class="header-menu-items sponsored">
|
||
<a class="header-menu-item" href="/hubs/build-ai-agents-that-are-ready-for-production/">Build AI Agents That Are Ready for Production</a>
|
||
</div>
|
||
</div>
|
||
<div class="header-menu-separator parent-category-separator"></div>
|
||
</nav>
|
||
</header>
|
||
|
||
<script>
|
||
const csrf = {
|
||
parameter: 'TH_CSRF',
|
||
header: 'X-TH-CSRF',
|
||
token: '-5035757795322894089'
|
||
}; // set csrf for auth-status script
|
||
</script>
|
||
<script>
|
||
addEventListener('DOMContentLoaded', function() {
|
||
handleRedirects();
|
||
handleMenus();
|
||
handleMobileMenuHeights();
|
||
handleGotoLinks();
|
||
});
|
||
|
||
function isHidden(element) {
|
||
try {
|
||
return window.getComputedStyle(element).display === 'none';
|
||
} catch (_) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
function getLink(element) {
|
||
if (element.hasAttribute('data-goto')) {
|
||
return element.getAttribute('data-goto');
|
||
}
|
||
return element.href;
|
||
}
|
||
|
||
function isLeftClick(event) {
|
||
if (event.altKey || event.shiftKey) {
|
||
return false;
|
||
} else if ('buttons' in event || 'which' in event) {
|
||
return event.buttons === 1 || event.which === 1;
|
||
} else {
|
||
return (event.button === 1 || (event.type === 'click'));
|
||
}
|
||
}
|
||
|
||
function handleRedirects() {
|
||
const redirections = [...document.querySelectorAll('[data-activate-menu]'), ...document.querySelectorAll('[data-click-target]')];
|
||
|
||
redirections.forEach(function(element) {
|
||
const menuSelector = element.getAttribute('data-activate-menu') || element.getAttribute('data-click-target');
|
||
const redirectingElement = document.querySelector(menuSelector);
|
||
if (redirectingElement) {
|
||
element.style.cursor = 'pointer';
|
||
const redirect = function(e) {
|
||
if (redirectingElement.hasAttribute('href') || redirectingElement.hasAttribute('data-goto')) {
|
||
if (redirectingElement.hasAttribute('data-new-window') || e.ctrlKey || e.metaKey) {
|
||
window.open(getLink(redirectingElement), '_blank');
|
||
} else {
|
||
window.open(getLink(redirectingElement), '_self');
|
||
}
|
||
} else {
|
||
const evt = new e.constructor(e.type, e);
|
||
redirectingElement.dispatchEvent(evt);
|
||
}
|
||
};
|
||
element.addEventListener('mouseup', redirect);
|
||
element.addEventListener('mousedown', (e) => e.preventDefault());
|
||
element.addEventListener('click', (e) => e.preventDefault());
|
||
}
|
||
});
|
||
}
|
||
|
||
function handleMenus() {
|
||
const menuElements = [
|
||
...document.querySelectorAll('.header-menu > a'),
|
||
...document.querySelectorAll('.header-menu > p.menu-label')
|
||
];
|
||
|
||
let scrollYMemory = -1;
|
||
|
||
function scrollToMemory() {
|
||
if (scrollYMemory !== -1) {
|
||
setTimeout(function() {
|
||
window.scrollTo(0, scrollYMemory);
|
||
scrollYMemory = -1;
|
||
}, 10);
|
||
}
|
||
}
|
||
|
||
function hideMenus() {
|
||
// unfocus menus & items, and set the menus to non-visible.
|
||
menuElements.forEach(function (element) {
|
||
element.blur();
|
||
element.parentElement.blur();
|
||
element.parentElement.classList.remove('menu-opened');
|
||
const menuItems = element.parentElement.querySelector('.header-menu-items');
|
||
if (menuItems) {
|
||
menuItems.style.display = 'none';
|
||
}
|
||
});
|
||
const wasHidden = document.body.style.overflowY === 'hidden';
|
||
document.body.style.overflowY = 'auto';
|
||
if (wasHidden) {
|
||
scrollToMemory();
|
||
}
|
||
}
|
||
|
||
function isEventOutsideMenu(e) {
|
||
return e.target.closest && !e.target.closest('.header-menu') && !e.target.closest('[data-activate-menu]');
|
||
}
|
||
|
||
// Handle mobile menu toggling
|
||
menuElements.forEach(function(element) {
|
||
const menu = element.parentElement;
|
||
const headerItems = menu.querySelector('.header-menu-items');
|
||
const menuEntries = headerItems ? headerItems.querySelectorAll('.header-menu-item') : [];
|
||
|
||
const focus = function() {
|
||
menu.focus();
|
||
menu.classList.add('menu-opened');
|
||
if (headerItems) {
|
||
headerItems.style.display = 'block';
|
||
}
|
||
if (menu.classList.contains('zone-menu')) {
|
||
scrollYMemory = window.scrollY;
|
||
document.body.style.overflowY = 'hidden';
|
||
} else {
|
||
scrollYMemory = -1;
|
||
}
|
||
};
|
||
|
||
const unfocus = function() {
|
||
menu.blur();
|
||
menu.classList.remove('menu-opened');
|
||
if (headerItems) {
|
||
headerItems.style.display = 'none';
|
||
}
|
||
const wasHidden = document.body.style.overflowY === 'hidden';
|
||
document.body.style.overflowY = 'auto';
|
||
if (wasHidden) {
|
||
scrollToMemory();
|
||
}
|
||
};
|
||
|
||
const toggleMenuVisibility = function(e) {
|
||
if ((e.type === 'click' || e.type === 'mouseup') && !isLeftClick(e)) {
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
const hidden = isHidden(headerItems);
|
||
if (menu.hasAttribute('data-click-activation')) { // handle click activated toggling
|
||
if (hidden) {
|
||
hideMenus(); // hide other open menus first
|
||
focus();
|
||
} else {
|
||
unfocus();
|
||
}
|
||
e.preventDefault();
|
||
} else if (hidden) {
|
||
hideMenus(); // hide other open menus first
|
||
focus();
|
||
e.preventDefault(); // prevent 'click' event from firing when menu is hidden
|
||
}
|
||
};
|
||
|
||
element.addEventListener('touchend', toggleMenuVisibility);
|
||
element.addEventListener('mouseup', toggleMenuVisibility);
|
||
|
||
// Add hover events to non-click-activated menus, even though CSS should cover it.
|
||
if (!menu.hasAttribute('data-click-activation')) {
|
||
menu.addEventListener('mouseover', function () {
|
||
hideMenus(); // hide other open menus first
|
||
focus();
|
||
});
|
||
|
||
menu.addEventListener('mouseout', function (e) {
|
||
if (isEventOutsideMenu(e)) {
|
||
unfocus();
|
||
}
|
||
});
|
||
}
|
||
|
||
// Hide menu when child is clicked
|
||
menuEntries.forEach(function(menuEntry) {
|
||
const linkToItem = function(e) {
|
||
if (e.type === 'mousedown' || e.type === 'click') {
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
if (e.type === 'mouseup' && !isLeftClick(e)) {
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
window.open(getLink(menuEntry), (e.ctrlKey || e.metaKey) ? '_blank' : (menuEntry.target || '_self'));
|
||
unfocus();
|
||
e.preventDefault();
|
||
};
|
||
|
||
const linkToMobileItem = function(e) {
|
||
if (e.type === 'touchstart') {
|
||
menuEntry.setAttribute('data-touchmove', false);
|
||
} else if (e.type === 'touchmove') {
|
||
menuEntry.setAttribute('data-touchmove', true);
|
||
} else if (e.type === 'touchend' && (!menuEntry.hasAttribute('data-touchmove') || menuEntry.getAttribute('data-touchmove').toLowerCase() === 'false')) {
|
||
window.open(getLink(menuEntry), (e.ctrlKey || e.metaKey) ? '_blank' : (menuEntry.target || '_self'));
|
||
unfocus();
|
||
e.preventDefault();
|
||
}
|
||
};
|
||
|
||
menuEntry.addEventListener('mousedown', linkToItem);
|
||
menuEntry.addEventListener('mouseup', linkToItem);
|
||
menuEntry.addEventListener('click', linkToItem);
|
||
menuEntry.addEventListener('touchstart', linkToMobileItem);
|
||
menuEntry.addEventListener('touchmove', linkToMobileItem);
|
||
menuEntry.addEventListener('touchend', linkToMobileItem);
|
||
});
|
||
});
|
||
|
||
function hideIfNonMenuBounds(e) {
|
||
if (isEventOutsideMenu(e)) {
|
||
hideMenus();
|
||
}
|
||
}
|
||
|
||
addEventListener('mousemove', hideIfNonMenuBounds);
|
||
addEventListener('touchend', hideIfNonMenuBounds);
|
||
addEventListener('mouseup', hideIfNonMenuBounds);
|
||
addEventListener('mousedown', hideIfNonMenuBounds);
|
||
addEventListener('click', hideIfNonMenuBounds);
|
||
}
|
||
|
||
function handleMobileMenuHeights() {
|
||
function setAppHeight() {
|
||
document.documentElement.style.setProperty('--app-height', window.innerHeight + 'px');
|
||
}
|
||
|
||
addEventListener('resize', function() {
|
||
setAppHeight();
|
||
});
|
||
|
||
setAppHeight();
|
||
}
|
||
|
||
function handleGotoLinks() {
|
||
// Add anchor mimicking to elements with data-goto attributes
|
||
// This addresses SEO concerns of linking to noindex pages by allowing JS to handle the URL
|
||
const anchorElements = document.querySelectorAll('*[data-goto]');
|
||
anchorElements.forEach((anchorElement) => {
|
||
anchorElement.addEventListener('mouseover', () => {
|
||
anchorElement.style.cursor = 'pointer';
|
||
anchorElement.style.textDecoration = 'underline';
|
||
});
|
||
anchorElement.addEventListener('mouseout', () => {
|
||
anchorElement.style.cursor = 'unset';
|
||
anchorElement.style.textDecoration = 'unset';
|
||
});
|
||
anchorElement.addEventListener('mouseup', (e) => {
|
||
e.preventDefault();
|
||
});
|
||
anchorElement.addEventListener('mousedown', (e) => {
|
||
e.preventDefault();
|
||
});
|
||
anchorElement.addEventListener('click', (e) => {
|
||
e.preventDefault();
|
||
const anchorHref = anchorElement.getAttribute('data-goto');
|
||
if (anchorElement.hasAttribute('data-new-window') || e.ctrlKey || e.metaKey) {
|
||
window.open(anchorHref, '_blank');
|
||
} else {
|
||
window.open(anchorHref, '_self');
|
||
}
|
||
});
|
||
});
|
||
}
|
||
</script><script>
|
||
const authenticatedBlock = document.querySelector('#authenticated-block');
|
||
const unauthenticatedBlock = document.querySelector('#unauthenticated-block');
|
||
|
||
let authenticated = {
|
||
isAuthenticated: false,
|
||
isAdmin: false,
|
||
user: {
|
||
id: null,
|
||
name: null,
|
||
url: null,
|
||
profileImage: null,
|
||
}
|
||
};
|
||
|
||
fetch('/services/internal/data/articles-getAuthenticationStatus', {
|
||
headers: {
|
||
'Accept': 'application/json'
|
||
}
|
||
})
|
||
.then(function (result) {
|
||
return result.json()
|
||
})
|
||
.then(function (result) {
|
||
const res = result.result.data
|
||
if (!res.authenticated) {
|
||
unauthenticatedBlock.classList.add('shown')
|
||
} else {
|
||
authenticated.user.id = res.id;
|
||
authenticated.user.name = res.realName;
|
||
authenticated.user.url = res.profileUrl;
|
||
authenticated.user.profileImage = res.avatar;
|
||
authenticated.user.jobTitle = res.jobTitle;
|
||
authenticated.user.companyName = res.companyName;
|
||
|
||
bindProps('#header-username', null, null, (res.firstName || res.username), null)
|
||
bindProps('#header-avatar', null, res.avatar, null, null)
|
||
bindProps('#header-user-plug', res.profileUrl, null, res.realName, null)
|
||
bindProps('#header-user-edit', '/users/' + res.id + '/edit.html', null, null, null)
|
||
bindProps('#header-dropdown-manage-email', '/newsletters/' + res.id + '/manage.html', null, null, null)
|
||
bindProps('#dropdown-view-profile', res.profileUrl, null, null, null)
|
||
bindProps('#drafts-link', '/users/' + res.id + '/drafts.html', null, null, null)
|
||
|
||
if (res.isAdmin) {
|
||
// Construct backwards so the #after call places elements in the correct order
|
||
const firstUserAction = document.querySelector('#first-user-action')
|
||
const adminConsoleItem = document.createElement('li')
|
||
const adminConsoleLink = createLink('/dzone/staff/index.html', 'Admin Console')
|
||
adminConsoleItem.appendChild(adminConsoleLink)
|
||
firstUserAction.after(adminConsoleItem)
|
||
|
||
const moderationItem = document.createElement('li')
|
||
const moderationLink = createLink('/moderation/list.html', 'Moderation')
|
||
moderationItem.appendChild(moderationLink)
|
||
firstUserAction.after(moderationItem)
|
||
|
||
const bountyModerationItem = document.createElement('li')
|
||
const bountyModerationLink = createLink('/moderation/bounties', 'Bounty Moderation')
|
||
bountyModerationItem.appendChild(bountyModerationLink)
|
||
firstUserAction.after(bountyModerationItem)
|
||
}
|
||
|
||
authenticated.isAuthenticated = res.authenticated;
|
||
authenticated.isAdmin = res.isAdmin;
|
||
|
||
authenticatedBlock.classList.add('shown')
|
||
}
|
||
}).catch(function (result) {
|
||
console.error(result)
|
||
})
|
||
|
||
/**
|
||
* Binds different properties to the selected element.
|
||
*
|
||
* @param selector - Selector to select the element
|
||
* @param href - href attribute value
|
||
* @param src - src attribute value
|
||
* @param innerHTML - innerHTML property value
|
||
* @param innerText - innerText property value
|
||
*/
|
||
function bindProps(selector, href, src, innerHTML, innerText) {
|
||
const element = document.querySelector(selector)
|
||
if (element) {
|
||
if (href) element.href = href
|
||
if (src) element.src = src
|
||
if (innerHTML) element.innerHTML = innerHTML
|
||
if (innerText) element.innerText = innerText
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Creates a new link element.
|
||
*
|
||
* @param href - href attribute value
|
||
* @param innerText - innerText property value
|
||
* @returns {HTMLAnchorElement} The generated link element
|
||
*/
|
||
function createLink(href, innerText) {
|
||
const link = document.createElement('a')
|
||
link.href = href
|
||
link.innerText = innerText
|
||
|
||
return link
|
||
}
|
||
</script><script>
|
||
const userHeader = document.querySelector('#user-header')
|
||
const userDropdown = document.querySelector('#user-dropdown')
|
||
const postDropdown = document.querySelector('#post-button')
|
||
const postMenu = document.querySelector('#post-menu')
|
||
|
||
let userDropdownOpen = false
|
||
let postDropdownOpen = false
|
||
|
||
document.addEventListener('click', function(event) {
|
||
if (postDropdown && postDropdown.contains(event.target)) {
|
||
setUserDropdown(false)
|
||
setPostDropdown(!postDropdownOpen)
|
||
} else if (userHeader && userHeader.contains(event.target)) {
|
||
setPostDropdown(false)
|
||
setUserDropdown(!userDropdownOpen)
|
||
} else {
|
||
setUserDropdown(false)
|
||
setPostDropdown(false)
|
||
}
|
||
})
|
||
|
||
function setUserDropdown(value) {
|
||
userDropdownOpen = value
|
||
if (userDropdownOpen) {
|
||
if (userDropdown) {
|
||
userDropdown.classList.add('open')
|
||
}
|
||
} else {
|
||
if (userDropdown) {
|
||
userDropdown.classList.remove('open')
|
||
}
|
||
}
|
||
}
|
||
|
||
function setPostDropdown(value) {
|
||
postDropdownOpen = value
|
||
if (postDropdownOpen) {
|
||
if (postMenu) {
|
||
postMenu.classList.add('open')
|
||
}
|
||
} else {
|
||
if (postMenu) {
|
||
postMenu.classList.remove('open')
|
||
}
|
||
}
|
||
}
|
||
</script><script>
|
||
document.addEventListener("alpine:init", () => {
|
||
Alpine.store('global', {
|
||
executeHttp(path, body, method) {
|
||
const options = {
|
||
method: method,
|
||
headers: {
|
||
[csrf.header]: csrf.token
|
||
}
|
||
};
|
||
|
||
if (method !== 'GET') {
|
||
options.body = JSON.stringify(body);
|
||
options.headers = {
|
||
...options.headers,
|
||
'Content-Type': 'application/json; charset=UTF-8'
|
||
};
|
||
}
|
||
|
||
return new Promise((resolve, reject) => {
|
||
fetch(path, options)
|
||
.then(res => {
|
||
if (!res.ok) {
|
||
reject(res);
|
||
} else {
|
||
resolve(res);
|
||
}
|
||
})
|
||
.catch(err => reject(err));
|
||
});
|
||
},
|
||
getFromService(path) {
|
||
return this.executeHttp(path, null, 'GET');
|
||
},
|
||
postToService(path, body = {}) {
|
||
return this.executeHttp(path, body, 'POST');
|
||
},
|
||
putToService(path, body = {}) {
|
||
return this.executeHttp(path, body, 'PUT');
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/colors.css">
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/article/styles.css">
|
||
|
||
|
||
|
||
|
||
|
||
<div id="body-container">
|
||
<div id="announcement-container-outer">
|
||
<div id="announcement-previous">
|
||
<i class="icon-angle-left"></i>
|
||
</div>
|
||
<div id="announcement-next">
|
||
<i class="icon-angle-right"></i>
|
||
</div>
|
||
<div id="announcement-container">
|
||
<div class="announcement announcement-count-1"
|
||
data-position="1">
|
||
<div class="body"><p><strong>Could your team report a vulnerability within 24 hours? </strong>Find out on September 23.</p></div>
|
||
<div class="spacer"></div>
|
||
<a href="https://cvent.me/O32zXR?utm_source=Announcements&utm_medium=DzoneWeb&utm_campaign=QtGroup-0923" target="_blank">
|
||
<button>Assess Your CRA Readiness</button>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script type="text/javascript" async>
|
||
(function() {
|
||
let announcementPosition = 1;
|
||
let minAnnouncementPosition = -1;
|
||
let maxAnnouncementPosition = -1;
|
||
|
||
const announcementPrevBtn = document.querySelector('#announcement-previous');
|
||
const announcementNextBtn = document.querySelector('#announcement-next');
|
||
|
||
function withAnnouncements(callback) {
|
||
const announcements = document.querySelectorAll('#announcement-container .announcement');
|
||
for (let announcement of announcements) {
|
||
callback(announcement);
|
||
}
|
||
}
|
||
|
||
function initAnnouncementVars() {
|
||
document.querySelector(':root').style.setProperty('--mobile-announcement-separator-width', '1px');
|
||
withAnnouncements(function(announcement) {
|
||
const pos = parseInt(announcement.getAttribute('data-position'));
|
||
minAnnouncementPosition = minAnnouncementPosition === -1 ? pos : Math.min(minAnnouncementPosition, pos);
|
||
maxAnnouncementPosition = maxAnnouncementPosition === -1 ? pos : Math.max(maxAnnouncementPosition, pos);
|
||
});
|
||
|
||
if (document.querySelector('.announcementBarContainer')) {
|
||
document.querySelector(':root').style.setProperty('--body-top-padding', '0');
|
||
}
|
||
|
||
if (maxAnnouncementPosition <= 0) {
|
||
document.querySelector(':root').style.setProperty('--body-top-padding', '0');
|
||
}
|
||
|
||
sizeToFullWhenOneEntryOnMobile();
|
||
}
|
||
|
||
function setAnnouncementPosition(position) {
|
||
if (window.outerWidth >= 890) {
|
||
return; // we do not need to change the position, since we can display everything on desktop.
|
||
}
|
||
|
||
// Make the announcement cyclical
|
||
if (minAnnouncementPosition !== -1 && maxAnnouncementPosition !== -1) {
|
||
if (position > maxAnnouncementPosition) {
|
||
position = minAnnouncementPosition; // overflow to the first announcement
|
||
} else if (position < minAnnouncementPosition) {
|
||
position = maxAnnouncementPosition; // underflow to the last announcement
|
||
}
|
||
announcementPosition = position;
|
||
}
|
||
|
||
const shownAnnouncements = [];
|
||
|
||
let reverseFlex = false; // should only be true when the first and last items are showing
|
||
|
||
// Now that the position is valid, apply the transforms
|
||
withAnnouncements(function(announcement) {
|
||
const pos = parseInt(announcement.getAttribute('data-position'));
|
||
const isWrapped = position === maxAnnouncementPosition && pos === minAnnouncementPosition; // showing first + last at same time
|
||
const doesNextQualify = window.outerWidth >= 500 && (pos === position + 1 || isWrapped);
|
||
|
||
if (pos === position || doesNextQualify) {
|
||
shownAnnouncements.push(announcement);
|
||
} else {
|
||
announcement.style.display = 'none';
|
||
}
|
||
|
||
announcement.style.opacity = 0.0;
|
||
|
||
if (isWrapped) {
|
||
reverseFlex = true;
|
||
}
|
||
});
|
||
|
||
for (let announcement of shownAnnouncements) {
|
||
announcement.style.display = 'flex';
|
||
announcement.style.opacity = 1.0;
|
||
}
|
||
|
||
const announcementContainer = document.querySelector('#announcement-container');
|
||
if (announcementContainer) {
|
||
announcementContainer.style.flexDirection = reverseFlex ? 'row-reverse' : 'row';
|
||
}
|
||
}
|
||
|
||
function resetAnnouncements() {
|
||
announcementPosition = 1;
|
||
const announcementContainer = document.querySelector('#announcement-container');
|
||
if (announcementContainer) {
|
||
announcementContainer.style.flexDirection = 'row';
|
||
}
|
||
withAnnouncements(function(announcement) {
|
||
announcement.style.opacity = 1.0;
|
||
announcement.style.display = 'flex';
|
||
});
|
||
}
|
||
|
||
function sizeToFullWhenOneEntryOnMobile() {
|
||
if (maxAnnouncementPosition <= 2 && announcementPrevBtn && announcementNextBtn) {
|
||
announcementPrevBtn.style.display = maxAnnouncementPosition === 2 && window.outerWidth < 500 ? 'flex' : 'none';
|
||
announcementNextBtn.style.display = maxAnnouncementPosition === 2 && window.outerWidth < 500 ? 'flex' : 'none';
|
||
}
|
||
if (maxAnnouncementPosition === 1 && window.outerWidth >= 500 && window.outerWidth < 890) {
|
||
document.querySelector(':root').style.setProperty('--mobile-announcement-separator-width', '0');
|
||
document.querySelector('#announcement-container .announcement').style.maxWidth = '100%';
|
||
}
|
||
}
|
||
|
||
function resetAnnouncementsOnResize() {
|
||
announcementPosition = 1; // we want to reset the announcement position every resize
|
||
if (window.outerWidth >= 890) { // 4 announcements can be shown (215px * 4) + separator padding
|
||
resetAnnouncements();
|
||
} else { // if we're still on mobile, set the position to normalize things after resize
|
||
setAnnouncementPosition(announcementPosition);
|
||
sizeToFullWhenOneEntryOnMobile();
|
||
}
|
||
}
|
||
|
||
window.addEventListener('resize', resetAnnouncementsOnResize);
|
||
|
||
initAnnouncementVars();
|
||
setAnnouncementPosition(announcementPosition); // sets the min & max positions as well as initializes transforms
|
||
|
||
if (announcementPrevBtn) {
|
||
announcementPrevBtn.onclick = function() {
|
||
setAnnouncementPosition(announcementPosition - 1);
|
||
};
|
||
}
|
||
|
||
if (announcementNextBtn) {
|
||
announcementNextBtn.onclick = function() {
|
||
setAnnouncementPosition(announcementPosition + 1);
|
||
};
|
||
}
|
||
})(); </script>
|
||
<div id="ftl-article" class="trending-article-body">
|
||
<aside class="trending-sidebar" aria-labelledby="related-sidebar-heading">
|
||
<div class="trending">
|
||
<h2 id="related-sidebar-heading">Related</h2>
|
||
<div class="trending-separator"></div>
|
||
<ul>
|
||
<li class="item">
|
||
<a href="/articles/how-we-optimize-fintech-microservices-on-kubernete" class="related-link">A Transaction-Grade Performance Blueprint for Spring Boot FinTech Microservices (Tracing, Histograms, and Kubernetes)</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/asynchronous-microservices-communication-kafka-spring-boot" class="related-link">Implementing Asynchronous Communication Between Microservices Using Kafka and Spring Boot</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/zero-downtime-java-kubernetes-deployments" class="related-link">Zero-Downtime Deployments for Java Apps on Kubernetes</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/application-deployment-strategies" class="related-link">Smart Deployment Strategies for Modern Applications</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</aside>
|
||
<div class="container-fluid body trending-article-fluid">
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<div class="articles-wrap">
|
||
<div class="ad-container">
|
||
<div id="div-gpt-ad-1435246566686-0" class="ads-billboard-article dz2_article_billboard_new" data-gpt-slot="top"></div>
|
||
</div>
|
||
|
||
|
||
<div class="article-stream widget-top-border">
|
||
<div class="article-main">
|
||
<div class="content-right-images">
|
||
<div id="div-gpt-ad-1435246566686-2" class="sidebar-ad dz2_article_halfpage_new" data-gpt-slot="sidebar1"></div>
|
||
<div class="trending-separator"></div>
|
||
<aside class="trending" aria-labelledby="trending-sidebar-heading">
|
||
<h2 id="trending-sidebar-heading">Trending</h2>
|
||
<ul>
|
||
<li class="item">
|
||
<a href="/articles/hakky54mutual-tls-1" class="trending-link" target="_self">How to Easily Set Up Mutual TLS SSL</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/scaling-ai-agents-kubernetes" class="trending-link" target="_self">Making Running Optional: Scaling AI Agents on Kubernetes With Agent Substrate</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/databricks-cache-improves-analytics-workloads" class="trending-link" target="_self">Improving Repeated Analytics Workloads With Databricks Disk Cache</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/working-code-technical-debt" class="trending-link" target="_self">The New Technical Debt: Working Code No One Can Explain</a>
|
||
</li>
|
||
</ul>
|
||
</aside>
|
||
</div>
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "Article",
|
||
"headline": "Chaos Engineering for Microservices",
|
||
"author": [{"image":{"@type":"ImageObject","caption":"Prabhu Chinnasamy","url":"https://secure.gravatar.com/avatar/118d76c1417d9ed63ea7562d5fc2de25?d=identicon&r=PG"},"@type":"Person","name":"Prabhu Chinnasamy","description":"Prabhu Chinnasamy is a seasoned Software Engineer with over 16 years of experience in Full-Stack Development, Cloud Architect, and Performance Engineering. As a Staff Software Engineer at Walmart, Prabhu has played a key role in large-scale projects like Walmart's WCNP cloud migration, CI/CD pipeline optimizations, and predictive modeling for performance insights. His expertise spans Kubernetes, Azure, Node.js, and Java. Passionate about leveraging AI for cloud automation and anomaly detection, Prabhu shares practical insights on scalable architectures, observability best practices, and performance tuning. IEEE Member and active contributor to technical communities.","url":"https://dzone.com/users/5292482/prabhucseirtt.html","sameAs":["https://www.linkedin.com/in/prabhucse/"]}],
|
||
"audience": "software developers",
|
||
"keywords": "",
|
||
"timeRequired": "PT10M",
|
||
"commentCount": -28,
|
||
"wordCount": "2301",
|
||
"accessMode": "textual, visual",
|
||
"datePublished": "2025-04-11T00:00:00Z",
|
||
|
||
"articleSection": "",
|
||
"publisher": {
|
||
"@type": "Organization",
|
||
"name": "DZone",
|
||
"url": "https://dzone.com",
|
||
"logo": {
|
||
"@type": "ImageObject",
|
||
"url": "https://dzone.com/themes/dz20/images/dz_logo_2021_cropped.png"
|
||
}
|
||
},
|
||
"articleBody": "As someone who works closely with distributed systems and microservices, I've seen firsthand how complex things can get once Kubernetes, Istio, and service meshes enter the picture. The shift to a cloud-native world is exciting, but it brings new challenges — especially around resilience. We can't just hope things won’t fail — because they will. That’s where chaos engineering comes in. It’s a proactive way to build confidence in your system’s ability to handle real-world disruptions by intentionally injecting failure and observing how everything holds up. As modern applications adopt microservices, Kubernetes, and service meshes like Istio, ensuring resilience becomes a critical challenge. Distributed architectures introduce new failure modes, which demand proactive testing to achieve high availability. Chaos engineering helps organizations identify and fix weaknesses before they impact users by introducing controlled failures to observe and improve system behavior. For Java (Spring Boot) and Node.js applications, tools like Chaos Toolkit, Chaos Monkey, and Istio-based fault injection offer powerful ways to put chaos engineering into practice. Kubernetes-native chaos experiments — including pod failures, network latency injection, and region-based disruptions — allow teams to stress-test system stability at scale. In this article, I’ll walk you through how we implemented chaos engineering across our stack using Chaos Toolkit, Chaos Monkey, and Istio — with hands-on examples for Java and Node.js. If you're exploring ways to strengthen system resilience, this guide is packed with practical insights you can apply today. What Is Chaos Engineering? Chaos engineering is a discipline designed to proactively identify weaknesses in distributed systems by simulating real-world failures. The goal is to strengthen application resilience by running controlled experiments that help teams: Simulate the failure of an entire region or data center.Inject latency between services.Max out CPU cores to evaluate performance impact.Simulate file system I/O faults.Test application behavior when dependencies become unavailable.Observe the cascading impact of outages on microservices. By incorporating chaos engineering practices, organizations can detect weaknesses before they impac t production, reducing downtime and improving system recovery time. Chaos Engineering Lifecycle The process of conducting chaos engineering experiments follows a structured lifecycle: Figure 1: The chaos engineering lifecycle: A systematic approach to improving system resilience through continuous experimentation. This lifecycle ensures that failures are introduced methodically and improvements are made continuously. Chaos Toolkit vs. Chaos Monkey: Key Differences Chaos Toolkit and Chaos Monkey are powerful tools in chaos engineering, but they have distinct use cases. Featurechaos toolkitchaos monkey for spring boot Purpose A versatile framework for multi-platform chaos testing Specifically designed for injecting failures in Spring Boot applications. Implementation Uses declarative JSON/YAML experiments. Configured via application.yml and Spring Boot actuator endpoints. Language Support Supports multiple environments and programming languages. Primarily designed for Java and Spring Boot applications. Types of Failures Injects network failures, pod terminations, latency, CPU stress, and custom-defined failures. Simulates latency, exceptions, and service failures Integration Works with Kubernetes, Istio, Azure, Prometheus, etc. Directly integrates with Spring Boot Actuator APIs. Configuration Requires defining experiments.json or experiments.yaml. Enabled using spring.profiles.active=chaos-monkey. When to Use Chaos Toolkit? When working with Kubernetes-based deployments.When requiring multi-cloud or multi-language chaos testing.When defining custom failure scenarios for distributed environments. When to Use Chaos Monkey? When testing Spring Boot applications.When needing application-layer failures such as method-level latency and exceptions.When preferring a lightweight, built-in solution for Java-based microservices. Chaos Toolkit: A Versatile Chaos Testing Framework Installation For Java and Node.js applications, install the Chaos Toolkit CLI: Plain Text pip install chaostoolkit To integrate Kubernetes-based chaos testing: Plain Text pip install chaostoolkit-kubernetes For Istio-based latency injection: Plain Text pip install -U chaostoolkit-istio To validate application health using Prometheus: Plain Text pip install -U chaostoolkit-prometheus Chaos Monkey for Spring Boot The below diagram illustrates how Chaos Monkey for Spring Boot integrates with different components of a Spring Boot application to inject failures and assess resilience. On the left, it shows the key layers of a typical Spring Boot application, including @Controller, @Repository, @Service, and @RestController, which represent the web, business logic, and data access layers. These components are continuously monitored by Chaos Monkey Watchers, which include Controller Watcher, Repository Watcher, Service Watcher, and RestController Watcher. These watchers track activity within their respective layers and enable Chaos Monkey to introduce failures dynamically. On the right, the diagram depicts different types of chaos assaults that can be triggered, such as Latency Assault, which introduces artificial delays in request processing; Exception Assault, which injects random exceptions into methods; and KillApp Assault, which simulates a complete application crash. By leveraging these chaos experiments, teams can validate how well their Spring Boot applications handle unexpected failures and improve system resilience. This visualization helps in understanding the failure injection points within a Spring Boot application and highlights how Chaos Monkey enables fault tolerance testing in real-world scenarios. Figure 2: Chaos Monkey in a Spring Boot Application: Injecting failures at different layers—Controller, Service, Repository — to test resilience. Installation Add the following dependency to your Spring Boot project (pom.xml): XML <dependency> <groupId>de.codecentric</groupId> <artifactId>chaos-monkey-spring-boot</artifactId> <version>2.5.4</version> </dependency> Enable Chaos Monkey in application.yml: YAML spring: profiles: active: chaos-monkey chaos: monkey: enabled: true assaults: level: 3 latency-active: true latency-range-start: 2000 latency-range-end: 5000 exceptions-active: true watcher: controller: true service: true repository: true Running Chaos Monkey in Spring Boot Start the application with: Plain Text mvn spring-boot:run -Dspring.profiles.active=chaos-monkey To manually enable Chaos Monkey attacks via Spring Boot Actuator endpoints: Plain Text curl -X POST http://localhost:8080/actuator/chaosmonkey/enable To introduce latency or exceptions, configure assaults dynamically: Plain Text curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \\ -H \"Content-Type: application/json\" \\ -d '{ \"latencyActive\": true, \"exceptionsActive\": true, \"level\": 5 }' Chaos Engineering in Node.js: Implementing Chaos Monkey and Chaos Toolkit While Chaos Monkey for Spring Boot is widely used for Java applications, Node.js applications can also integrate chaos engineering principles using Chaos Toolkit and Node-specific libraries. Chaos Monkey for Node.js For Node.js applications, the Chaos Monkey functionality can be introduced using third-party libraries. Installation for Node.js To install the Chaos Monkey library for Node.js: JavaScript npm install chaos-monkey --save Basic Usage in a Node.js Application JavaScript const express = require(\"express\"); const chaosMonkey = require(\"chaos-monkey\"); const app = express(); app.use(chaosMonkey()); // Injects random failures app.get(\"/\", (req, res) => { res.send(\"Hello, Chaos Monkey!\"); }); app.listen(3000, () => { console.log(\"App running on port 3000\"); }); What does this do? Injects random latency delays.Throws random exceptions in endpoints.Simulates network failures. Configuring Chaos Monkey for Controlled Experiments in Node.js To have more control over chaos injection, you can define specific failure types. Configuring Failure Injection chaosMonkey.config.js: JavaScript module.exports = { latency: { enabled: true, minMs: 500, maxMs: 3000, }, exceptions: { enabled: true, probability: 0.2, // 20% chance of exception }, killProcess: { enabled: false, // Prevents killing the process }, }; Now, modify the server.js file to load the configuration: JavaScript const express = require(\"express\"); const chaosMonkey = require(\"chaos-monkey\"); const config = require(\"./chaosMonkey.config\"); const app = express(); app.use(chaosMonkey(config)); // Inject failures based on configuration app.get(\"/\", (req, res) => { res.send(\"Chaos Engineering in Node.js is running!\"); }); app.listen(3000, () => { console.log(\"App running on port 3000 with Chaos Monkey\"); }); Chaos Toolkit for Node.js Applications Similar to Kubernetes and Java applications, Chaos Toolkit can be used to inject failures into Node.js services. Example: Latency Injection for Node.js using Chaos Toolkit This Chaos Toolkit experiment will introduce latency into a Node.js service. JSON { \"title\": \"Introduce artificial latency in Node.js service\", \"description\": \"Test how the Node.js API handles slow responses.\", \"method\": [ { \"type\": \"action\", \"name\": \"introduce-latency\", \"provider\": { \"type\": \"process\", \"path\": \"curl\", \"arguments\": [ \"-X\", \"POST\", \"http://localhost:3000/chaosmonkey/enable-latency\" ] } } ], \"rollbacks\": [ { \"type\": \"action\", \"name\": \"remove-latency\", \"provider\": { \"type\": \"process\", \"path\": \"curl\", \"arguments\": [ \"-X\", \"POST\", \"http://localhost:3000/chaosmonkey/disable-latency\" ] } } ] } To execute and report the experiment: JSON chaos run node-latency-experiment.json --journal-path=node-latency-journal.json chaos report --export-format=json node-latency-journal.json > node-latency-report.json Chaos Experiments in Multi-Cloud and Kubernetes Environments For microservices deployed on Kubernetes or multi-cloud platforms, Chaos Toolkit provides a more robust way to perform failover testing. Figure 3: Chaos toolkit experiment execution flow: A structured approach to injecting failures and observing system behavior. For microservices deployed on Kubernetes or multi-cloud platforms, Chaos Toolkit provides a more robust way to perform failover testing. A pod-kill experiment to test application resilience in Kubernetes: JSON { \"version\": \"1.0.0\", \"title\": \"System Resilience to Pod Failures\", \"description\": \"Can the system survive a pod failure?\", \"configuration\": { \"app_name\": { \"type\": \"env\", \"key\": \"APP_NAME\" }, \"namespace\": { \"type\": \"env\", \"key\": \"NAMESPACE\" } }, \"steady-state-hypothesis\": { \"title\": \"Application must be up and healthy\", \"probes\": [{ \"name\": \"check-application-health\", \"type\": \"probe\", \"provider\": { \"type\": \"http\", \"url\": \"http://myapp.com/health\", \"method\": \"GET\" } }] }, \"method\": [{ \"type\": \"action\", \"name\": \"terminate-pod\", \"provider\": { \"type\": \"python\", \"module\": \"chaosk8s.pod.actions\", \"func\": \"terminate_pods\", \"arguments\": { \"label_selector\": \"app=${app_name}\", \"ns\": \"${namespace}\", \"rand\": true, \"mode\": \"fixed\", \"qty\": 1 } } }] } Running the Chaos Experiment To execute the experiment, run: JSON chaos run pod-kill-experiment.json --journal-path=pod-kill-experiment-journal.json To generate a report after execution: JSON chaos report --export-format=html pod-kill-experiment-journal.json > pod-kill-experiment-report.html Rolling back the experiment (if necessary): JSON chaos rollback pod-kill-experiment.json Example: Region Delay Experiment (Kubernetes and Istio) This experiment injects network latency into requests by modifying Istio’s virtual service. YAML version: \"1.0.0\" title: \"Region Delay Experiment\" description: \"Simulating high latency in a specific region\" method: - type: action name: \"inject-fault\" provider: type: python module: chaosistio.fault.actions func: add_delay_fault arguments: virtual_service_name: \"my-service-vs\" fixed_delay: \"5s\" percentage: 100 ns: \"default\" pauses: before: 5 after: 20 rollbacks: - type: action name: \"remove-fault\" provider: type: python module: chaosistio.fault.actions func: remove_delay_fault arguments: virtual_service_name: \"my-service-vs\" ns: \"default\" To execute: JSON chaos run region-delay-experiment.yaml --journal-path=region-delay-journal.json Generate a detailed report: HTML chaos report --export-format=html region-delay-journal.json > region-delay-report.html Figure 4: Multi-cloud chaos engineering: Simulating cloud-region failures across AWS, Azure, and GCP using a global load balancer. More Chaos Toolkit Scenarios In addition to basic pod failures and latency injection, Chaos Toolkit can simulate more complex failure scenarios: Injecting memory/CPU stress in Kubernetes pods: Test how applications behave under high CPU or memory consumption.Shutting down a database instance: Simulate a database failure to verify if the system can handle database outages gracefully.Network partitioning between services: Introduce network partitions to analyze the impact on microservices communication.Scaling down an entire service: Reduce the number of available replicas of a service to test auto-scaling mechanisms.Time-based failures: Simulate failures only during peak traffic hours to observe resilience under load. These real-world scenarios help identify weak points in distributed architectures and improve recovery strategies. Integrating Chaos Engineering into CI/CD Pipelines To ensure that resilience testing becomes an integral part of the software development lifecycle, organizations should automate chaos experiments within CI/CD pipelines. This allows failures to be introduced in a controlled manner before production deployment, reducing the risk of unexpected outages. Why Integrate Chaos Testing into CI/CD? Automates resilience validation as part of deployment.Identifies performance bottlenecks before changes reach production.Ensures services can recover from failures without manual intervention.Improves Mean Time to Recovery (MTTR) by simulating real-world issues. Chaos Engineering in CI/CD Workflow A typical CI/CD-integrated chaos testing workflow follows these steps: Developer commits code: Code changes are pushed to the repository.CI/CD pipeline triggers build and deploy: The application is built and deployed to Kubernetes.Run chaos experiments: Automated chaos testing is executed after deployment.Observability and monitoring: Prometheus, Datadog, and logs collect system behavior metrics.Verify system resilience: If service health checks pass, the deployment proceeds.Rollback if needed: If the system fails resilience thresholds, auto-rollback is triggered. Figure 5: Integrating Chaos Engineering into CI/CD: Automating resilience testing with Kubernetes and Istio. Example: Automating Chaos Testing in GitHub Actions Below is an example of how you can automate Chaos Toolkit experiments in a GitHub Actions CI/CD pipeline: YAML name: Chaos Testing Pipeline on: push: branches: - main jobs: chaos-test: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v2 - name: Install Chaos Toolkit run: pip install chaostoolkit - name: Run Chaos Experiment run: chaos run pod-kill-experiment.json - name: Validate Recovery run: curl -f http://myapp.com/health || exit 1 Key steps explained: The pipeline triggers code push events.The Chaos Toolkit is installed dynamically.The pod-kill experiment is executed against the deployed application.A health check ensures the application recovers from the failure.If the health check fails, the pipeline halts the deployment to avoid releasing unstable code. Validating Results After Running Chaos Experiments After executing chaos experiments, it’s essential to validate system performance. The chaos report command generates detailed experiment reports: JSON chaos report --export-format=html /app/reports/chaos_experiment_journal.json /app/reports/chaos_experiment_summary.html How to analyze results? If the system maintains a steady state → The service is resilient.If anomalies are detected → Logs, monitoring tools, and alerting mechanisms should be used for debugging.If failure cascades occur → Adjust service design, introduce circuit breakers, or optimize auto-scaling policies. Best Practices for Running Chaos Experiments Start with a steady-state hypothesis: Define what a \"healthy\" system looks like before introducing chaos.Begin with low-level failures: Start with 100ms latency injection before increasing failure severity.Monitor system metrics: Use Grafana and Prometheus dashboards to track failure impact.Enable auto-rollbacks: Ensure failures are reverted automatically after an experiment.Gradually increase chaos level: Use controlled chaos before introducing large-scale failures. Conclusion For adopting Chaos Engineering, one thing became clear to me: it's not just about breaking things — it's about building trust in our systems. Whether you're running Java, Node.js, Kubernetes, or Istio, these practices give you a controlled way to test your application’s limits and prepare for the unexpected. By incorporating tools like Chaos Monkey and Chaos Toolkit and combining them with Kubernetes-native chaos experiments, we’ve been able to validate failovers, test latency handling, and even simulate region-level outages - all without putting production at risk. If you’re just starting, take it step by step. Start small, automate experiments where possible, and track everything. The end goal isn’t chaos — it’s confidence. Thanks for reading, and happy chaos engineering! References Principles of Chaos Engineering – Foundational concepts and lifecycleChaos Toolkit Documentation – Official docs and pluginsChaos Monkey for Spring Boot – Failure injection for Java microservicesChaos Engineering on Kubernetes – Real-world guide by KubernetesIstio Fault Injection – Network and delay simulation in service mesh",
|
||
"mainEntityOfPage": {
|
||
"@type": "WebPage",
|
||
"@id": "https://dzone.com/articles/chaos-engineering-for-microservices"
|
||
},
|
||
"image": {
|
||
"@type": "ImageObject",
|
||
"url": "https://dz2cdn1.dzone.com/storage/article-thumb/18334696-thumb.jpg"
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "BreadcrumbList",
|
||
"itemListElement": [
|
||
{
|
||
"@type": "ListItem",
|
||
"position": 1,
|
||
"name": "DZone",
|
||
"item": "https://dzone.com"
|
||
},
|
||
{
|
||
"@type": "ListItem",
|
||
"position": 2,
|
||
"name": "Software Design and Architecture",
|
||
"item": "https://dzone.com/software-design-and-architecture"
|
||
},
|
||
{
|
||
"@type": "ListItem",
|
||
"position": 3,
|
||
"name": "Microservices",
|
||
"item": "https://dzone.com/microservices"
|
||
},
|
||
{
|
||
"@type": "ListItem",
|
||
"position": 4,
|
||
"name": "Chaos Engineering for Microservices",
|
||
"item": "https://dzone.com/articles/chaos-engineering-for-microservices"
|
||
}
|
||
]
|
||
}
|
||
|
||
</script>
|
||
|
||
<article>
|
||
<div class="content">
|
||
<div class="header">
|
||
<ol class="breadcrumb">
|
||
<li class="server"><a href="https://dzone.com">DZone</a></li>
|
||
<li class="server"><a href="https://dzone.com/software-design-and-architecture">Software Design and Architecture</a></li>
|
||
<li class="server"><a href="https://dzone.com/microservices">Microservices</a></li>
|
||
<li class="active server">Chaos Engineering for Microservices</li>
|
||
</ol>
|
||
|
||
|
||
<div class="header-title">
|
||
<div class="title">
|
||
<h1 class="article-title">Chaos Engineering for Microservices</h1>
|
||
</div>
|
||
|
||
<div class="subhead">
|
||
<p>Learn how to implement chaos engineering using Chaos Toolkit and Chaos Monkey for Java (Spring Boot), Node.js, Kubernetes, and Istio to enhance system resilience.</p>
|
||
</div>
|
||
|
||
<div class="publish-meta">
|
||
By<span style="user-select: none;"> </span>
|
||
<div class="article-author-meta">
|
||
<img src="https://dz2cdn1.dzone.com/thumbnail?fid=18282857&w=80" class="avatar" alt="Prabhu Chinnasamy user avatar" width="40">
|
||
<div class="author-info">
|
||
<span class="author-name">
|
||
<a href="/users/5292482/prabhucseirtt.html" rel="nofollow" data-core-user="false">Prabhu Chinnasamy</a>
|
||
</span>
|
||
</div>
|
||
|
||
|
||
|
||
·
|
||
</div>
|
||
<span class="author-date">
|
||
Apr. 11, 25
|
||
</span>
|
||
·
|
||
<span>Analysis</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="author-n-useraction">
|
||
<div class="like action" x-data="engagementModal(articleId)">
|
||
<span id="activity-like-icon" class="dz-like icon-thumbs-up" x-on:click="updateStore()"></span>
|
||
<span class="action-label like-text" x-on:click="open()" x-cloak>
|
||
<span>Likes</span>
|
||
<span id="activity-like-counter" class="like-count">(57)</span>
|
||
</span>
|
||
<template x-teleport="body">
|
||
<div class="engagement-overlay" x-show="$store.article.engagement.open && nodeId === $store.article.id" x-on:keyup.escape.window="close()">
|
||
<div class="engagement-modal">
|
||
<div class="inner" x-on:click.outside="close()">
|
||
<div class="header">
|
||
<div class="title">Likes</div>
|
||
<button class="close" x-on:click="close()"></button>
|
||
</div>
|
||
<div class="content">
|
||
<div x-show="$store.article.engagement.initializing" class="loading-screen">
|
||
<i class="icon icon-spin3 anim-spin"></i>
|
||
</div>
|
||
<div x-show="!$store.article.engagement.initializing">
|
||
<template x-for="user in $store.article.engagement.users" :key="user.id">
|
||
<div class="media">
|
||
<div class="media-left">
|
||
<img class="avatar"
|
||
x-bind:src="user.profile.profileImage"
|
||
loading="lazy"
|
||
width="50"
|
||
height="50"
|
||
>
|
||
</div>
|
||
<div class="media-right">
|
||
<a x-bind:href="user.computed.url" x-html="user.profile.name"></a>
|
||
<div x-show="formatJobData(user)" x-html="formatJobData(user)"></div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
<div x-show="isDataUnavailable()" class="center-screen">
|
||
<div x-show="!$store.article.engagement.unauthorized">
|
||
<div>There are no likes...yet! 👀</div>
|
||
<div>Be the first to like this post!</div>
|
||
</div>
|
||
<div x-show="$store.article.engagement.unauthorized">
|
||
<div>It looks like you're not logged in.</div>
|
||
<div><a href="/users/login.html">Sign in</a> to see who liked this post!</div>
|
||
</div>
|
||
</div>
|
||
<div x-show="isFooterShowing()">
|
||
<div class="footer">
|
||
<button class="btn btn-primary" x-on:click="fetchEngagements()"
|
||
x-bind:disabled="$store.article.engagement.loading"
|
||
>
|
||
Load More
|
||
<i x-show="$store.article.engagement.loading" class="icon icon-spin3 anim-spin"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template> </div>
|
||
|
||
<div class="action comment-action">
|
||
<span class="comment">
|
||
<i class="icon-comment"></i>
|
||
<span class="action-label">Comment</span>
|
||
<span id="activity-comment-counter" class="comment-count"></span>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="save action">
|
||
<div id="activity-save-icon" class="save icon-star-empty">
|
||
<span id="activity-save-text" class="action-label">Save</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tweet action">
|
||
<a id="tweet-link" href="" class="title" target="_blank">
|
||
<span><i class="icon-twitter"></i></span>
|
||
<span class="action-label">Tweet</span>
|
||
</a>
|
||
</div>
|
||
|
||
<div class="linkedin action">
|
||
<a id="linkedin-link" href="https://www.linkedin.com/sharing/share-offsite/?url=https://dzone.com/articles/chaos-engineering-for-microservices" class="title" target="_blank">
|
||
<span><i class="icon-linkedin-1"></i></span>
|
||
<span class="action-label">Share</span>
|
||
</a>
|
||
</div>
|
||
|
||
<div class="right-most">
|
||
<div id="activity-view-container" class="article-views action">
|
||
<i class="icon-eye"></i>
|
||
<span class="action-label view-count">14.6K Views</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="signin-prompt">
|
||
<p>Join the DZone community and get the full member experience.</p>
|
||
<a id="article-signin-prompt" href="/static/registration.html">Join For Free</a>
|
||
</div>
|
||
<div class="arrow-down"></div>
|
||
|
||
<div id="top-bumper-container"></div>
|
||
|
||
<div>
|
||
<div class="content-html"><p>As someone who works closely with distributed systems and microservices, I've seen firsthand how complex things can get once Kubernetes, Istio, and service meshes enter the picture. The shift to a cloud-native world is exciting, but it brings new challenges — especially around resilience.</p>
|
||
<p>We can't just hope things won’t fail — because they will. That’s where chaos engineering comes in. It’s a proactive way to build confidence in your system’s ability to handle real-world disruptions by intentionally injecting failure and observing how everything holds up.</p>
|
||
<p>As modern applications adopt microservices, Kubernetes, and service meshes like Istio, ensuring resilience becomes a critical challenge. Distributed architectures introduce new failure modes, which demand proactive testing to achieve high availability. Chaos engineering helps organizations identify and fix weaknesses before they impact users by introducing controlled failures to observe and improve system behavior.</p>
|
||
<p>For Java (Spring Boot) and Node.js applications, tools like Chaos Toolkit, Chaos Monkey, and Istio-based fault injection offer powerful ways to put chaos engineering into practice. Kubernetes-native chaos experiments — including pod failures, network latency injection, and region-based disruptions — allow teams to stress-test system stability at scale.</p>
|
||
<p>In this article, I’ll walk you through how we implemented chaos engineering across our stack using Chaos Toolkit, Chaos Monkey, and Istio — with hands-on examples for Java and Node.js. If you're exploring ways to strengthen system resilience, this guide is packed with practical insights you can apply today.</p>
|
||
<h2>What Is Chaos Engineering?</h2>
|
||
<p dir="ltr"><a href="https://dzone.com/articles/getting-started-with-chaos-engineering">Chaos engineering</a> is a discipline designed to proactively identify weaknesses in distributed systems by simulating real-world failures. The goal is to strengthen application resilience by running controlled experiments that help teams:</p>
|
||
<ul>
|
||
<li dir="ltr">Simulate the failure of an entire region or data center.</li>
|
||
<li dir="ltr">Inject latency between services.</li>
|
||
<li dir="ltr">Max out CPU cores to evaluate performance impact.</li>
|
||
<li dir="ltr">Simulate file system I/O faults.</li>
|
||
<li dir="ltr">Test application behavior when dependencies become unavailable.</li>
|
||
<li dir="ltr">Observe the cascading impact of outages on microservices.</li>
|
||
</ul>
|
||
<p dir="ltr">By incorporating chaos engineering practices, organizations can detect weaknesses before they impac <strong>t production,</strong> reducing downtime and improving system recovery time.</p>
|
||
<h2 dir="ltr">Chaos Engineering Lifecycle</h2>
|
||
<p dir="ltr">The process of conducting chaos engineering experiments follows a structured lifecycle:</p>
|
||
<p dir="ltr"><img data-image="true" data-new="false" data-sizeformatted="149.6 kB" data-mimetype="image/png" data-creationdate="1742061368161" data-creationdateformatted="03/15/2025 05:56 PM" data-type="temp" data-url="https://dz2cdn1.dzone.com/storage/temp/18280874-chaos-engineeringlifecycle.png" data-modificationdate="null" data-size="149590" data-name="chaos-engineeringlifecycle.png" data-id="18280874" alt="Chaos Engineering LifeCycle Diagram" class="fr-fic fr-dib lazyload" style="width: 580px;" data-src="https://dz2cdn1.dzone.com/storage/temp/18280874-chaos-engineeringlifecycle.png"></p>
|
||
<p><em>Figure 1: The chaos engineering lifecycle: A systematic approach to improving system resilience through continuous experimentation.</em></p>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">This lifecycle ensures that failures are introduced methodically and improvements are made continuously.</p>
|
||
<h2 dir="ltr">Chaos Toolkit vs. Chaos Monkey: Key Differences</h2>
|
||
<p dir="ltr"><strong>Chaos Toolkit </strong>and <strong>Chaos Monkey</strong> are powerful tools in chaos engineering, but they have distinct use cases.</p>
|
||
<div align="left" dir="ltr">
|
||
<div class="table-responsive" style="border: none;">
|
||
<table style="max-width: 100%; width: auto; table-layout: fixed; display: table;" width="auto">
|
||
<thead>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<th style="overflow-wrap: break-word; width: auto;" width="auto">Feature</th>
|
||
<th style="overflow-wrap: break-word; width: auto;" width="auto">chaos toolkit</th>
|
||
<th style="overflow-wrap: break-word; width: auto;" width="auto">chaos monkey for spring boot</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Purpose</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">A versatile framework for multi-platform chaos testing</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Specifically designed for injecting failures in <strong>Spring Boot applications.</strong></p></td>
|
||
</tr>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Implementation</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Uses declarative <strong>JSON/YAML</strong> experiments.</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Configured via application.yml and Spring Boot actuator endpoints.</p></td>
|
||
</tr>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Language Support</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Supports multiple environments and programming languages.</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Primarily designed for Java and Spring Boot applications.</p></td>
|
||
</tr>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Types of Failures</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Injects <strong> network failures, pod terminations, latency, CPU stress, and custom-defined failures.</strong></p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Simulates latency, exceptions, and service failures</p></td>
|
||
</tr>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Integration</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Works with <strong>Kubernetes, Istio, Azure, Prometheus, etc.</strong></p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Directly integrates with <strong>Spring Boot Actuator APIs.</strong></p></td>
|
||
</tr>
|
||
<tr style="overflow-wrap: break-word; width: auto;" width="auto">
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Configuration</p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Requires defining <strong>experiments.json or experiments.yaml.</strong></p></td>
|
||
<td style="overflow-wrap: break-word; width: auto; background-color: rgb(255, 255, 255);" width="auto">
|
||
<p dir="ltr">Enabled using spring.profiles.active=chaos-monkey.</p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><br></p>
|
||
</div>
|
||
</div>
|
||
<h2 dir="ltr"><strong>When to Use Chaos Toolkit?</strong></h2>
|
||
<ul>
|
||
<li dir="ltr">When working with Kubernetes-based deployments.</li>
|
||
<li dir="ltr">When requiring multi-cloud or multi-language chaos testing.</li>
|
||
<li dir="ltr">When defining custom failure scenarios for distributed environments.</li>
|
||
</ul>
|
||
<h2 dir="ltr"><strong>When to Use Chaos Monkey?</strong></h2>
|
||
<ul>
|
||
<li dir="ltr">When testing Spring Boot applications.</li>
|
||
<li dir="ltr">When needing application-layer failures such as method-level latency and exceptions.</li>
|
||
<li dir="ltr">When preferring a lightweight, built-in solution for Java-based microservices.</li>
|
||
</ul>
|
||
<h2 dir="ltr"><strong>Chaos Toolkit: A Versatile Chaos Testing Framework</strong></h2>
|
||
<h3 dir="ltr"><strong>Installation</strong></h3>
|
||
<p dir="ltr">For Java and Node.js applications, install the Chaos Toolkit CLI:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="pip install chaostoolkit " data-lang="text/plain">
|
||
<pre> <code lang="text/plain">pip install chaostoolkit </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">To integrate Kubernetes-based chaos testing:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="pip install chaostoolkit-kubernetes " data-lang="text/plain">
|
||
<pre> <code lang="text/plain">pip install chaostoolkit-kubernetes </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">For Istio-based latency injection:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="pip install -U chaostoolkit-istio " data-lang="text/plain">
|
||
<pre> <code lang="text/plain">pip install -U chaostoolkit-istio </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">To validate application health using Prometheus:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="pip install -U chaostoolkit-prometheus " data-lang="text/plain">
|
||
<pre> <code lang="text/plain">pip install -U chaostoolkit-prometheus </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<h2 dir="ltr"><strong>Chaos Monkey for Spring Boot</strong></h2>
|
||
<p dir="ltr">The below diagram illustrates how Chaos Monkey for Spring Boot integrates with different components of a Spring Boot application to inject failures and assess resilience. </p>
|
||
<p dir="ltr">On the left, it shows the key layers of a typical Spring Boot application, including <code>@Controller</code>, <code>@Repository</code>, <code>@Service</code>, and <code>@RestController</code>, which represent the web, business logic, and data access layers. These components are continuously monitored by <strong>Chaos Monkey Watchers</strong>, which include Controller Watcher, Repository Watcher, Service Watcher, and RestController Watcher. These watchers track activity within their respective layers and enable Chaos Monkey to introduce failures dynamically. </p>
|
||
<p dir="ltr">On the right, the diagram depicts different types of chaos assaults that can be triggered, such as Latency Assault, which introduces artificial delays in request processing; Exception Assault, which injects random exceptions into methods; and KillApp Assault, which simulates a complete application crash. By leveraging these chaos experiments, teams can validate how well their Spring Boot applications handle unexpected failures and improve system resilience. This visualization helps in understanding the failure injection points within a Spring Boot application and highlights how Chaos Monkey enables fault tolerance testing in real-world scenarios.</p>
|
||
<p><img data-image="true" data-new="false" data-sizeformatted="189.9 kB" data-mimetype="image/jpeg" data-creationdate="1741712611880" data-creationdateformatted="03/11/2025 05:03 PM" data-type="temp" data-url="https://dz2cdn1.dzone.com/storage/temp/18270660-compress-springboot.jpg" data-modificationdate="null" data-size="189867" data-name="compress-springboot.jpg" data-id="18270660" data-src="https://dz2cdn1.dzone.com/storage/temp/18270660-compress-springboot.jpg" alt="Chaos Monkey in a Spring Boot Application Diagram" class="fr-fic fr-dib lazyload" style="width: 746px;"></p>
|
||
<div style="text-align: center;">
|
||
<em>Figure 2: Chaos Monkey in a Spring Boot Application: Injecting failures at different layers—Controller, Service, Repository — to test resilience.</em>
|
||
</div>
|
||
<p><br></p>
|
||
<h3><strong>Installation</strong></h3>
|
||
<p dir="ltr">Add the following dependency to your Spring Boot project (pom.xml):</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
XML
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="
|
||
<dependency>
|
||
<groupId>de.codecentric</groupId>
|
||
<artifactId>chaos-monkey-spring-boot</artifactId>
|
||
<version>2.5.4</version>
|
||
</dependency>" data-lang="application/xml">
|
||
<pre> <code lang="application/xml"><dependency>
|
||
<groupId>de.codecentric</groupId>
|
||
<artifactId>chaos-monkey-spring-boot</artifactId>
|
||
<version>2.5.4</version>
|
||
</dependency></code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">Enable Chaos Monkey in application.yml:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
YAML
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="spring:
|
||
profiles:
|
||
active: chaos-monkey
|
||
chaos:
|
||
monkey:
|
||
enabled: true
|
||
assaults:
|
||
level: 3
|
||
latency-active: true
|
||
latency-range-start: 2000
|
||
latency-range-end: 5000
|
||
exceptions-active: true
|
||
watcher:
|
||
controller: true
|
||
service: true
|
||
repository: true" data-lang="text/x-yaml">
|
||
<pre> <code lang="text/x-yaml">spring:
|
||
profiles:
|
||
active: chaos-monkey
|
||
chaos:
|
||
monkey:
|
||
enabled: true
|
||
assaults:
|
||
level: 3
|
||
latency-active: true
|
||
latency-range-start: 2000
|
||
latency-range-end: 5000
|
||
exceptions-active: true
|
||
watcher:
|
||
controller: true
|
||
service: true
|
||
repository: true</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<h2 dir="ltr"><strong>Running Chaos Monkey in Spring Boot</strong></h2>
|
||
<p dir="ltr">Start the application with:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="mvn spring-boot:run -Dspring.profiles.active=chaos-monkey " data-lang="text/plain">
|
||
<pre> <code lang="text/plain">mvn spring-boot:run -Dspring.profiles.active=chaos-monkey </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">To manually enable Chaos Monkey attacks via Spring Boot Actuator endpoints:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="curl -X POST http://localhost:8080/actuator/chaosmonkey/enable" data-lang="text/plain">
|
||
<pre> <code lang="text/plain">curl -X POST http://localhost:8080/actuator/chaosmonkey/enable</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">To introduce latency or exceptions, configure assaults dynamically:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
Plain Text
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \ -H "Content-Type: application/json" \ -d '{ "latencyActive": true, "exceptionsActive": true, "level": 5 }'" data-lang="text/plain">
|
||
<pre> <code lang="text/plain">curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \ -H "Content-Type: application/json" \ -d '{ "latencyActive": true, "exceptionsActive": true, "level": 5 }'</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<h2 dir="ltr"><strong>Chaos Engineering in Node.js: Implementing Chaos Monkey and Chaos Toolkit</strong></h2>
|
||
<p dir="ltr">While Chaos Monkey for Spring Boot is widely used for Java applications, Node.js applications can also integrate chaos engineering principles using Chaos Toolkit and Node-specific libraries.</p>
|
||
<h3 dir="ltr"><strong>Chaos Monkey for Node.js</strong></h3>
|
||
<p dir="ltr"><span style="margin: 0px; padding: 0px;">For Node.js applications, the Chaos Monkey functionality can be introduced using third-party libraries.</span></p>
|
||
<h4 dir="ltr"><strong>Installation for Node.js</strong></h4>
|
||
<p dir="ltr">To install the Chaos Monkey library for Node.js:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JavaScript
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="npm install chaos-monkey --save " data-lang="text/javascript">
|
||
<pre> <code lang="text/javascript">npm install chaos-monkey --save </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<h4 dir="ltr"><strong>Basic Usage in a Node.js Application</strong></h4>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JavaScript
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="const express = require("express");
|
||
const chaosMonkey = require("chaos-monkey");
|
||
const app = express();
|
||
app.use(chaosMonkey()); // Injects random failures
|
||
app.get("/", (req, res) => {
|
||
res.send("Hello, Chaos Monkey!");
|
||
});
|
||
app.listen(3000, () => {
|
||
console.log("App running on port 3000");
|
||
});" data-lang="text/javascript">
|
||
<pre> <code lang="text/javascript">const express = require("express");
|
||
const chaosMonkey = require("chaos-monkey");
|
||
const app = express();
|
||
app.use(chaosMonkey()); // Injects random failures
|
||
app.get("/", (req, res) => {
|
||
res.send("Hello, Chaos Monkey!");
|
||
});
|
||
app.listen(3000, () => {
|
||
console.log("App running on port 3000");
|
||
});</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr"><strong>What does this do?</strong></p>
|
||
<ul>
|
||
<li dir="ltr">Injects random latency delays.</li>
|
||
<li dir="ltr">Throws random exceptions in endpoints.</li>
|
||
<li dir="ltr">Simulates network failures.</li>
|
||
</ul>
|
||
<h2 dir="ltr"><strong>Configuring Chaos Monkey for Controlled Experiments in Node.js</strong></h2>
|
||
<p dir="ltr">To have more control <strong>over chaos injection</strong>, you can define specific failure types.</p>
|
||
<h3 dir="ltr"><strong>Configuring Failure Injection</strong></h3>
|
||
<p dir="ltr">chaosMonkey.config.js:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JavaScript
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="module.exports = {
|
||
latency: {
|
||
enabled: true,
|
||
minMs: 500,
|
||
maxMs: 3000,
|
||
},
|
||
exceptions: {
|
||
enabled: true,
|
||
probability: 0.2, // 20% chance of exception
|
||
},
|
||
killProcess: {
|
||
enabled: false, // Prevents killing the process
|
||
},
|
||
};" data-lang="text/javascript">
|
||
<pre> <code lang="text/javascript">module.exports = {
|
||
latency: {
|
||
enabled: true,
|
||
minMs: 500,
|
||
maxMs: 3000,
|
||
},
|
||
exceptions: {
|
||
enabled: true,
|
||
probability: 0.2, // 20% chance of exception
|
||
},
|
||
killProcess: {
|
||
enabled: false, // Prevents killing the process
|
||
},
|
||
};</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">Now, modify the server.js file to load the configuration:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JavaScript
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="const express = require("express");
|
||
const chaosMonkey = require("chaos-monkey");
|
||
const config = require("./chaosMonkey.config");
|
||
const app = express();
|
||
app.use(chaosMonkey(config)); // Inject failures based on configuration
|
||
app.get("/", (req, res) => {
|
||
res.send("Chaos Engineering in Node.js is running!");
|
||
});
|
||
|
||
app.listen(3000, () => {
|
||
console.log("App running on port 3000 with Chaos Monkey");
|
||
});" data-lang="text/javascript">
|
||
<pre> <code lang="text/javascript">const express = require("express");
|
||
const chaosMonkey = require("chaos-monkey");
|
||
const config = require("./chaosMonkey.config");
|
||
const app = express();
|
||
app.use(chaosMonkey(config)); // Inject failures based on configuration
|
||
app.get("/", (req, res) => {
|
||
res.send("Chaos Engineering in Node.js is running!");
|
||
});
|
||
|
||
app.listen(3000, () => {
|
||
console.log("App running on port 3000 with Chaos Monkey");
|
||
});</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<h2 dir="ltr"><strong>Chaos Toolkit for Node.js Applications</strong></h2>
|
||
<p dir="ltr">Similar to Kubernetes and Java applications, Chaos Toolkit can be used to inject failures into Node.js services.</p>
|
||
<h3 dir="ltr"><strong>Example: Latency Injection for Node.js using Chaos Toolkit</strong></h3>
|
||
<p dir="ltr">This Chaos Toolkit experiment will introduce latency into a Node.js service.</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="{
|
||
"title": "Introduce artificial latency in Node.js service",
|
||
"description": "Test how the Node.js API handles slow responses.",
|
||
"method": [
|
||
{
|
||
"type": "action",
|
||
"name": "introduce-latency",
|
||
"provider": {
|
||
"type": "process",
|
||
"path": "curl",
|
||
"arguments": [
|
||
"-X",
|
||
"POST",
|
||
"http://localhost:3000/chaosmonkey/enable-latency"
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"rollbacks": [
|
||
{
|
||
"type": "action",
|
||
"name": "remove-latency",
|
||
"provider": {
|
||
"type": "process",
|
||
"path": "curl",
|
||
"arguments": [
|
||
"-X",
|
||
"POST",
|
||
"http://localhost:3000/chaosmonkey/disable-latency"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}" data-lang="application/json">
|
||
<pre> <code lang="application/json">{
|
||
"title": "Introduce artificial latency in Node.js service",
|
||
"description": "Test how the Node.js API handles slow responses.",
|
||
"method": [
|
||
{
|
||
"type": "action",
|
||
"name": "introduce-latency",
|
||
"provider": {
|
||
"type": "process",
|
||
"path": "curl",
|
||
"arguments": [
|
||
"-X",
|
||
"POST",
|
||
"http://localhost:3000/chaosmonkey/enable-latency"
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"rollbacks": [
|
||
{
|
||
"type": "action",
|
||
"name": "remove-latency",
|
||
"provider": {
|
||
"type": "process",
|
||
"path": "curl",
|
||
"arguments": [
|
||
"-X",
|
||
"POST",
|
||
"http://localhost:3000/chaosmonkey/disable-latency"
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">To execute and report the experiment:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos run node-latency-experiment.json --journal-path=node-latency-journal.json
|
||
|
||
chaos report --export-format=json node-latency-journal.json > node-latency-report.json" data-lang="application/json">
|
||
<pre> <code lang="application/json">chaos run node-latency-experiment.json --journal-path=node-latency-journal.json
|
||
|
||
chaos report --export-format=json node-latency-journal.json > node-latency-report.json</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<h2 dir="ltr"><strong>Chaos Experiments in Multi-Cloud and Kubernetes Environments</strong></h2>
|
||
<p dir="ltr">For microservices deployed on Kubernetes or multi-cloud platforms, Chaos Toolkit provides a more robust way to perform failover testing.</p>
|
||
<p><img data-image="true" data-new="false" data-sizeformatted="167.9 kB" data-mimetype="image/png" data-creationdate="1741713033103" data-creationdateformatted="03/11/2025 05:10 PM" data-type="temp" data-url="https://dz2cdn1.dzone.com/storage/temp/18270665-observability-stack.png" data-modificationdate="null" data-size="167921" data-name="observability-stack.png" data-id="18270665" data-src="https://dz2cdn1.dzone.com/storage/temp/18270665-observability-stack.png" alt="Chaos Toolkit Experiment Execution Flow Diagram" class="fr-fic fr-dib lazyload" style="width: 539px;"></p>
|
||
<div style="text-align: center;">
|
||
<em>Figure 3: Chaos toolkit experiment execution flow: A structured approach to injecting failures and observing system behavior.</em>
|
||
</div>
|
||
<p><br></p>
|
||
<p>For microservices deployed on Kubernetes or multi-cloud platforms, Chaos Toolkit provides a more robust way to perform failover testing.</p>
|
||
<p dir="ltr">A <strong>pod-kill experiment</strong> to test application resilience in Kubernetes:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="{
|
||
"version": "1.0.0",
|
||
"title": "System Resilience to Pod Failures",
|
||
"description": "Can the system survive a pod failure?",
|
||
"configuration": {
|
||
"app_name": { "type": "env", "key": "APP_NAME" },
|
||
"namespace": { "type": "env", "key": "NAMESPACE" }
|
||
},
|
||
"steady-state-hypothesis": {
|
||
"title": "Application must be up and healthy",
|
||
"probes": [{
|
||
"name": "check-application-health",
|
||
"type": "probe",
|
||
"provider": {
|
||
"type": "http",
|
||
"url": "http://myapp.com/health",
|
||
"method": "GET"
|
||
}
|
||
}]
|
||
},
|
||
"method": [{
|
||
"type": "action",
|
||
"name": "terminate-pod",
|
||
"provider": {
|
||
"type": "python",
|
||
"module": "chaosk8s.pod.actions",
|
||
"func": "terminate_pods",
|
||
"arguments": {
|
||
"label_selector": "app=${app_name}",
|
||
"ns": "${namespace}",
|
||
"rand": true,
|
||
"mode": "fixed",
|
||
"qty": 1
|
||
}
|
||
}
|
||
}]
|
||
}" data-lang="application/json">
|
||
<pre> <code lang="application/json">{
|
||
"version": "1.0.0",
|
||
"title": "System Resilience to Pod Failures",
|
||
"description": "Can the system survive a pod failure?",
|
||
"configuration": {
|
||
"app_name": { "type": "env", "key": "APP_NAME" },
|
||
"namespace": { "type": "env", "key": "NAMESPACE" }
|
||
},
|
||
"steady-state-hypothesis": {
|
||
"title": "Application must be up and healthy",
|
||
"probes": [{
|
||
"name": "check-application-health",
|
||
"type": "probe",
|
||
"provider": {
|
||
"type": "http",
|
||
"url": "http://myapp.com/health",
|
||
"method": "GET"
|
||
}
|
||
}]
|
||
},
|
||
"method": [{
|
||
"type": "action",
|
||
"name": "terminate-pod",
|
||
"provider": {
|
||
"type": "python",
|
||
"module": "chaosk8s.pod.actions",
|
||
"func": "terminate_pods",
|
||
"arguments": {
|
||
"label_selector": "app=${app_name}",
|
||
"ns": "${namespace}",
|
||
"rand": true,
|
||
"mode": "fixed",
|
||
"qty": 1
|
||
}
|
||
}
|
||
}]
|
||
}</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<h3 dir="ltr"><strong>Running the Chaos Experiment</strong></h3>
|
||
<p dir="ltr">To execute the experiment, run:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos run pod-kill-experiment.json --journal-path=pod-kill-experiment-journal.json " data-lang="application/json">
|
||
<pre> <code lang="application/json">chaos run pod-kill-experiment.json --journal-path=pod-kill-experiment-journal.json </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">To generate a report after execution:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos report --export-format=html pod-kill-experiment-journal.json > pod-kill-experiment-report.html " data-lang="application/json">
|
||
<pre> <code lang="application/json">chaos report --export-format=html pod-kill-experiment-journal.json > pod-kill-experiment-report.html </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">Rolling back the experiment (if necessary):</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos rollback pod-kill-experiment.json " data-lang="application/json">
|
||
<pre> <code lang="application/json">chaos rollback pod-kill-experiment.json </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<h3 dir="ltr"><strong>Example: Region Delay Experiment (Kubernetes and Istio)</strong></h3>
|
||
<p dir="ltr">This experiment injects <strong>network latency</strong> into requests by modifying Istio’s virtual service.</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
YAML
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="version: "1.0.0"
|
||
title: "Region Delay Experiment"
|
||
description: "Simulating high latency in a specific region"
|
||
method:
|
||
- type: action
|
||
name: "inject-fault"
|
||
provider:
|
||
type: python
|
||
module: chaosistio.fault.actions
|
||
func: add_delay_fault
|
||
arguments:
|
||
virtual_service_name: "my-service-vs"
|
||
fixed_delay: "5s"
|
||
percentage: 100
|
||
ns: "default"
|
||
pauses:
|
||
before: 5
|
||
after: 20
|
||
rollbacks:
|
||
- type: action
|
||
name: "remove-fault"
|
||
provider:
|
||
type: python
|
||
module: chaosistio.fault.actions
|
||
func: remove_delay_fault
|
||
arguments:
|
||
virtual_service_name: "my-service-vs"
|
||
ns: "default"" data-lang="text/x-yaml">
|
||
<pre> <code lang="text/x-yaml">version: "1.0.0"
|
||
title: "Region Delay Experiment"
|
||
description: "Simulating high latency in a specific region"
|
||
method:
|
||
- type: action
|
||
name: "inject-fault"
|
||
provider:
|
||
type: python
|
||
module: chaosistio.fault.actions
|
||
func: add_delay_fault
|
||
arguments:
|
||
virtual_service_name: "my-service-vs"
|
||
fixed_delay: "5s"
|
||
percentage: 100
|
||
ns: "default"
|
||
pauses:
|
||
before: 5
|
||
after: 20
|
||
rollbacks:
|
||
- type: action
|
||
name: "remove-fault"
|
||
provider:
|
||
type: python
|
||
module: chaosistio.fault.actions
|
||
func: remove_delay_fault
|
||
arguments:
|
||
virtual_service_name: "my-service-vs"
|
||
ns: "default"</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">To execute:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos run region-delay-experiment.yaml --journal-path=region-delay-journal.json " data-lang="application/json">
|
||
<pre> <code lang="application/json">chaos run region-delay-experiment.yaml --journal-path=region-delay-journal.json </code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">Generate a detailed report:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
HTML
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos report --export-format=html region-delay-journal.json > region-delay-report.html" data-lang="text/html">
|
||
<pre> <code lang="text/html">chaos report --export-format=html region-delay-journal.json > region-delay-report.html</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p><img data-image="true" data-new="false" data-sizeformatted="118.2 kB" data-mimetype="image/png" data-creationdate="1741713173286" data-creationdateformatted="03/11/2025 05:12 PM" data-type="temp" data-url="https://dz2cdn1.dzone.com/storage/temp/18270666-multi-cloud-engineering.png" data-modificationdate="null" data-size="118206" data-name="multi-cloud-engineering.png" data-id="18270666" data-src="https://dz2cdn1.dzone.com/storage/temp/18270666-multi-cloud-engineering.png" alt="Multi-Cloud Chaos Engineering Diagram" class="fr-fic fr-dib lazyload" style="width: 637px;"></p>
|
||
<p dir="ltr" style="text-align: center;"><em>Figure 4: Multi-cloud chaos engineering: Simulating cloud-region failures across AWS, Azure, and GCP using a global load balancer.</em></p>
|
||
<p dir="ltr"><br></p>
|
||
<h2 dir="ltr">More Chaos Toolkit Scenarios</h2>
|
||
<p dir="ltr">In addition to basic pod failures and latency injection, Chaos Toolkit can simulate more complex failure scenarios:</p>
|
||
<ul>
|
||
<li dir="ltr"><strong>Injecting memory/CPU stress in Kubernetes pods</strong>: Test how applications behave under high CPU or memory consumption.</li>
|
||
<li dir="ltr"><strong>Shutting down a database instance</strong>: Simulate a database failure to verify if the system can handle database outages gracefully.</li>
|
||
<li dir="ltr"><strong>Network partitioning between services</strong>: Introduce network partitions to analyze the impact on microservices communication.</li>
|
||
<li dir="ltr"><strong>Scaling down an entire service</strong>: Reduce the number of available replicas of a service to test auto-scaling mechanisms.</li>
|
||
<li dir="ltr"><strong>Time-based failures</strong>: Simulate failures only during peak traffic hours to observe resilience under load.</li>
|
||
</ul>
|
||
<p dir="ltr">These real-world scenarios help identify weak points in distributed architectures and improve recovery strategies.</p>
|
||
<h2 dir="ltr">Integrating Chaos Engineering into CI/CD Pipelines</h2>
|
||
<p dir="ltr">To ensure that resilience testing becomes an integral part of the software development lifecycle, organizations should <strong>automate chaos experiments</strong> within CI/CD pipelines. This allows failures to be introduced in a controlled manner before production deployment, reducing the risk of unexpected outages.</p>
|
||
<h3 dir="ltr">Why Integrate Chaos Testing into CI/CD?</h3>
|
||
<ul>
|
||
<li dir="ltr">Automates resilience validation as part of deployment.</li>
|
||
<li dir="ltr">Identifies performance bottlenecks before changes reach production.</li>
|
||
<li dir="ltr">Ensures services can recover from failures without manual intervention.</li>
|
||
<li dir="ltr">Improves <strong>Mean Time to Recovery (MTTR)</strong> by simulating real-world issues.</li>
|
||
</ul>
|
||
<h3 dir="ltr">Chaos Engineering in CI/CD Workflow</h3>
|
||
<p dir="ltr">A typical CI/CD-integrated chaos testing workflow follows these steps:</p>
|
||
<ul>
|
||
<li dir="ltr"><strong>Developer commits code</strong>: Code changes are pushed to the repository.</li>
|
||
<li dir="ltr"><strong>CI/CD pipeline triggers build and deploy</strong>: The application is built and deployed to Kubernetes.</li>
|
||
<li dir="ltr"><strong>Run chaos experiments</strong>: Automated chaos testing is executed after deployment.</li>
|
||
<li dir="ltr"><strong>Observability and monitoring</strong>: Prometheus, Datadog, and logs collect system behavior metrics.</li>
|
||
<li dir="ltr"><strong>Verify system resilience</strong>: If service health checks pass, the deployment proceeds.</li>
|
||
<li dir="ltr"><strong>Rollback if needed</strong>: If the system fails resilience thresholds, auto-rollback is triggered.</li>
|
||
</ul>
|
||
<p dir="ltr"><img data-image="true" data-new="false" data-sizeformatted="206.9 kB" data-mimetype="image/png" data-creationdate="1741714315951" data-creationdateformatted="03/11/2025 05:31 PM" data-type="temp" data-url="https://dz2cdn1.dzone.com/storage/temp/18270672-1741714315186.png" data-modificationdate="null" data-size="206918" data-name="1741714315186.png" data-id="18270672" data-src="https://dz2cdn1.dzone.com/storage/temp/18270672-1741714315186.png" alt="Diagram of Integrating Chaos Engineering into CI/CD flow" class="fr-fic fr-dib lazyload" style="width: 720px;"></p>
|
||
<p dir="ltr" style="text-align: center;"><em>Figure 5: Integrating Chaos Engineering into CI/CD: Automating resilience testing with Kubernetes and Istio.</em></p>
|
||
<p dir="ltr"><br></p>
|
||
<h3 dir="ltr">Example: Automating Chaos Testing in GitHub Actions</h3>
|
||
<p dir="ltr">Below is an example of how you can automate Chaos Toolkit experiments in a GitHub Actions CI/CD pipeline:</p>
|
||
<div class="codeMirror-wrapper" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
YAML
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="name: Chaos Testing Pipeline
|
||
on:
|
||
push:
|
||
branches:
|
||
- main
|
||
jobs:
|
||
chaos-test:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- name: Checkout Code
|
||
uses: actions/checkout@v2
|
||
- name: Install Chaos Toolkit
|
||
run: pip install chaostoolkit
|
||
- name: Run Chaos Experiment
|
||
run: chaos run pod-kill-experiment.json
|
||
- name: Validate Recovery
|
||
run: curl -f http://myapp.com/health || exit 1" data-lang="text/x-yaml">
|
||
<pre> <code lang="text/x-yaml">name: Chaos Testing Pipeline
|
||
on:
|
||
push:
|
||
branches:
|
||
- main
|
||
jobs:
|
||
chaos-test:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- name: Checkout Code
|
||
uses: actions/checkout@v2
|
||
- name: Install Chaos Toolkit
|
||
run: pip install chaostoolkit
|
||
- name: Run Chaos Experiment
|
||
run: chaos run pod-kill-experiment.json
|
||
- name: Validate Recovery
|
||
run: curl -f http://myapp.com/health || exit 1</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p dir="ltr"><br></p>
|
||
<p dir="ltr">Key steps explained:</p>
|
||
<ul>
|
||
<li dir="ltr">The pipeline triggers <strong>code push</strong> events.</li>
|
||
<li dir="ltr">The <strong>Chaos Toolkit</strong> is installed dynamically.</li>
|
||
<li dir="ltr">The <strong>pod-kill experiment</strong> is executed against the deployed application.</li>
|
||
<li dir="ltr">A <strong>health check</strong> ensures the application recovers from the failure.</li>
|
||
<li dir="ltr">If the health check fails, the pipeline <strong>halts the deployment</strong> to avoid releasing unstable code.</li>
|
||
</ul>
|
||
<h3 dir="ltr">Validating Results After Running Chaos Experiments</h3>
|
||
<p dir="ltr">After executing chaos experiments, it’s essential to <strong>validate system performance</strong>. The <strong>chaos report</strong> command generates detailed experiment reports:</p>
|
||
<div class="codeMirror-wrapper newest" contenteditable="false">
|
||
<div contenteditable="false">
|
||
<div class="codeHeader">
|
||
<div class="nameLanguage">
|
||
JSON
|
||
</div><i class="icon-cancel-circled-1 cm-remove"> </i>
|
||
</div>
|
||
<div class="codeMirror-code--wrapper" data-code="chaos report --export-format=html /app/reports/chaos_experiment_journal.json /app/reports/chaos_experiment_summary.html" data-lang="application/json">
|
||
<pre> <code lang="application/json">chaos report --export-format=html /app/reports/chaos_experiment_journal.json /app/reports/chaos_experiment_summary.html</code>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><br></p>
|
||
<p dir="ltr">How to analyze results?</p>
|
||
<ul>
|
||
<li dir="ltr">If the system maintains a steady state → The service is resilient.</li>
|
||
<li dir="ltr">If anomalies are detected → Logs, monitoring tools, and alerting mechanisms should be used for debugging.</li>
|
||
<li dir="ltr">If failure cascades occur → Adjust service design, introduce circuit breakers, or optimize auto-scaling policies.</li>
|
||
</ul>
|
||
<h2 dir="ltr">Best Practices for Running Chaos Experiments</h2>
|
||
<ol>
|
||
<li dir="ltr"><strong>Start with a steady-state hypothesis</strong>: Define what a "healthy" system looks like before introducing chaos.</li>
|
||
<li dir="ltr"><strong>Begin with low-level failures</strong>: Start with 100ms latency injection before increasing failure severity.</li>
|
||
<li dir="ltr"><strong>Monitor system metrics</strong>: Use Grafana and Prometheus dashboards to track failure impact.</li>
|
||
<li dir="ltr"><strong>Enable auto-rollbacks</strong>: Ensure failures are reverted automatically after an experiment.</li>
|
||
<li dir="ltr"><strong>Gradually increase chaos level</strong>: Use controlled chaos before introducing large-scale failures.</li>
|
||
</ol>
|
||
<h2>Conclusion</h2>
|
||
<p>For adopting Chaos Engineering, one thing became clear to me: it's not just about breaking things — it's about building trust in our systems. Whether you're running <strong>Java, Node.js, Kubernetes, or Istio</strong>, these practices give you a controlled way to test your application’s limits and prepare for the unexpected.</p>
|
||
<p>By incorporating tools like <strong>Chaos Monkey</strong> and <strong>Chaos Toolkit</strong> and combining them with Kubernetes-native chaos experiments, we’ve been able to validate failovers, test latency handling, and even simulate region-level outages - all without putting production at risk.</p>
|
||
<p>If you’re just starting, take it step by step. Start small, automate experiments where possible, and track everything. The end goal isn’t chaos — it’s confidence.</p>
|
||
<p dir="ltr">Thanks for reading, and happy chaos engineering!</p>
|
||
<h2><strong>References</strong></h2>
|
||
<ul>
|
||
<li><a href="https://principlesofchaos.org/" rel="noopener noreferrer" target="_blank">Principles of Chaos Engineering</a> – Foundational concepts and lifecycle</li>
|
||
<li><a href="https://chaostoolkit.org/" rel="noopener noreferrer" target="_blank">Chaos Toolkit Documentation</a> – Official docs and plugins</li>
|
||
<li><a href="https://codecentric.github.io/chaos-monkey-spring-boot/" rel="noopener noreferrer" target="_blank">Chaos Monkey for Spring Boot</a> – Failure injection for Java microservices</li>
|
||
<li><a href="https://kubernetes.io/blog/2018/12/31/chaos-engineering/" rel="noopener noreferrer" target="_blank">Chaos Engineering on Kubernetes</a> – Real-world guide by Kubernetes</li>
|
||
<li><a href="https://istio.io/latest/docs/tasks/traffic-management/fault-injection/" rel="noopener noreferrer" target="_blank">Istio Fault Injection</a> – Network and delay simulation in service mesh</li>
|
||
</ul></div>
|
||
</div>
|
||
|
||
<div id="bottom-bumper-container"></div>
|
||
<div class="article-tag-pill-container">
|
||
<span class="article-tag-pill">Chaos Monkey</span>
|
||
<span class="article-tag-pill">Chaos engineering</span>
|
||
<span class="article-tag-pill">Kubernetes</span>
|
||
<span class="article-tag-pill">Spring Boot</span>
|
||
<span class="article-tag-pill">microservices</span>
|
||
</div>
|
||
|
||
<div class="attribution">
|
||
<p>Opinions expressed by DZone contributors are their own.</p>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
|
||
<div class="trending-separator goto"></div>
|
||
<aside class="trending goto" aria-labelledby="related-mobile-heading">
|
||
<h2 id="related-mobile-heading">Related</h2>
|
||
<ul>
|
||
<li class="item">
|
||
<a href="/articles/how-we-optimize-fintech-microservices-on-kubernete" class="goto-link related-link">A Transaction-Grade Performance Blueprint for Spring Boot FinTech Microservices (Tracing, Histograms, and Kubernetes)</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/asynchronous-microservices-communication-kafka-spring-boot" class="goto-link related-link">Implementing Asynchronous Communication Between Microservices Using Kafka and Spring Boot</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/zero-downtime-java-kubernetes-deployments" class="goto-link related-link">Zero-Downtime Deployments for Java Apps on Kubernetes</a>
|
||
</li>
|
||
<li class="item">
|
||
<a href="/articles/application-deployment-strategies" class="goto-link related-link">Smart Deployment Strategies for Modern Applications</a>
|
||
</li>
|
||
</ul>
|
||
</aside>
|
||
</div>
|
||
|
||
<div id="div-gpt-ad-1435246566686-11" class="ads-bottom-leaderboard dz2_article_bottom" data-gpt-slot="bottom"></div>
|
||
<div class="layout-card widget-top-border partner-resources-block" style="width:100%; margin-bottom: 1em;">
|
||
<div class="main-container">
|
||
<div class="featured-header">
|
||
<h2>
|
||
<span>Partner Resources</span>
|
||
</h2>
|
||
</div>
|
||
<div class="partner-resources-container">
|
||
<div id="div-gpt-ad-1435246566686-5" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr1"></div>
|
||
<div id="div-gpt-ad-1435246566686-6" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr2"></div>
|
||
<div id="div-gpt-ad-1435246566686-7" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr3"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bottom-sticky-ad-container">
|
||
<span class="bottom-sticky-ad-close" title="close"
|
||
x-on:click="$el.parentElement.classList.add('closed')">×</span>
|
||
<div id="div-gpt-ad-1635294790718-12" class="bottom-sticky-ad dz2_sticky_footer_leaderboard" data-gpt-slot="bottomStickyFooter"></div>
|
||
</div>
|
||
|
||
<div class="modal fade bd-example-modal-lg" id="modal-message" tabindex="-1" role="dialog" aria-hidden="true">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content">
|
||
<div class="modal-header"></div>
|
||
<div class="modal-body"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="comments-overlay"></div>
|
||
<div id="comment-box">
|
||
<div class="comment-box-wrapper">
|
||
<div id="comment-input-editor"></div>
|
||
</div>
|
||
<div class="info hidden"></div>
|
||
<div class="comments-content" style="display: none;">
|
||
<div class="comment-header">
|
||
<hr />
|
||
<span class="icon-comment">
|
||
<span class="numOfComments"></span> Comments
|
||
</span>
|
||
</div>
|
||
<div class="comments"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script async>var articleTitle = 'Chaos Engineering for Microservices';
|
||
var articleUrl = 'https://dzone.com/articles/chaos-engineering-for-microservices';
|
||
|
||
var retweetLink = document.querySelector('#tweet-link');
|
||
|
||
function retweet(event) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
|
||
var twitter = 'https://twitter.com/intent/tweet';
|
||
var params = '?text=' + encodeURIComponent(articleTitle) + '&url=' + articleUrl + '&ref=dzone.com&via=DZoneInc';
|
||
var win = window.open(twitter + params, '_blank');
|
||
win.focus();
|
||
}
|
||
|
||
retweetLink.addEventListener('click', retweet);
|
||
|
||
function showStatusMessage(options) {
|
||
var modal = document.getElementById('modal-message');
|
||
|
||
if(modal) {
|
||
modal.classList.add(options.type);
|
||
var modalBody = modal.querySelector('.modal-content .modal-body');
|
||
var modalHeader = modal.querySelector('.modal-content .modal-header');
|
||
|
||
modalHeader.innerText = options.header ? options.header : '';
|
||
modalBody.innerText = options.body ? options.body : '';
|
||
|
||
$(modal).modal('show');
|
||
|
||
$(modal).on('hidden.bs.modal', function () {
|
||
modal.classList.remove(options.type);
|
||
});
|
||
}
|
||
}
|
||
|
||
function showConfirmMessage(options) {
|
||
var modal = document.getElementById('modal-message');
|
||
|
||
if(modal) {
|
||
modal.classList.add(options.type);
|
||
var modalBody = modal.querySelector('.modal-content .modal-body');
|
||
var modalHeader = modal.querySelector('.modal-content .modal-header');
|
||
|
||
modalHeader.innerText = options.header ? options.header : '';
|
||
modalBody.innerText = options.body ? options.body : '';
|
||
|
||
if (options.textarea) {
|
||
var textareaDiv = document.createElement('div');
|
||
var textareaLabel = document.createElement('label');
|
||
textareaLabel.setAttribute('for', 'modal-textarea');
|
||
textareaLabel.innerText = options.textarea.label;
|
||
|
||
var textarea = document.createElement('textarea');
|
||
textarea.id = 'modal-textarea';
|
||
textarea.placeholder = (options.textarea.placeholder || '');
|
||
textarea.setAttribute('rows', (options.textarea.rows || 3));
|
||
textarea.classList.add('form-control', 'not-resizable');
|
||
|
||
if (options.textarea.maxlength) {
|
||
textarea.maxLength = options.textarea.maxlength;
|
||
}
|
||
|
||
textareaDiv.appendChild(textareaLabel);
|
||
textareaDiv.appendChild(textarea);
|
||
modalBody.appendChild(textareaDiv);
|
||
}
|
||
|
||
var btnContainer = document.createElement('div');
|
||
btnContainer.classList.add('btn-container');
|
||
|
||
var noBtn = document.createElement('button');
|
||
noBtn.innerText = options.noBtnText ? options.noBtnText : 'No';
|
||
noBtn.classList.add('no-btn');
|
||
|
||
var yesBtn = document.createElement('button');
|
||
yesBtn.innerText = options.yesBtnText ? options.yesBtnText : 'Yes';
|
||
yesBtn.classList.add('yes-btn');
|
||
|
||
btnContainer.appendChild(noBtn);
|
||
btnContainer.appendChild(yesBtn);
|
||
|
||
modalBody.appendChild(btnContainer);
|
||
|
||
$(modal).modal('show');
|
||
|
||
$(noBtn).one('click', function() {
|
||
$(modal).modal('hide');
|
||
|
||
if(options.noCallback) {
|
||
$(modal).one('hidden.bs.modal', function () {
|
||
options.noCallback();
|
||
});
|
||
}
|
||
});
|
||
|
||
$(yesBtn).one('click', function() {
|
||
$(modal).modal('hide');
|
||
|
||
if(options.yesCallback) {
|
||
$(modal).one('hidden.bs.modal', function () {
|
||
options.yesCallback();
|
||
});
|
||
}
|
||
});
|
||
|
||
$(modal).on('hidden.bs.modal', function () {
|
||
modal.classList.remove(options.type);
|
||
});
|
||
}
|
||
}
|
||
|
||
function getSuspensionBody() {
|
||
return 'We regret to inform you that your DZone account has been suspended for violating our Guidelines. ' +
|
||
'Please reach out to editors@dzone.com if you would like additional information.';
|
||
}</script>
|
||
<style>.engagement-overlay {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
background: rgb(0, 0, 0, 0.5);
|
||
z-index: 10000;
|
||
}
|
||
|
||
.engagement-modal {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: fixed;
|
||
z-index: 10;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.engagement-modal .inner {
|
||
background-color: white;
|
||
border-radius: 0.5em;
|
||
margin: auto;
|
||
border: 1px solid #cccccc;
|
||
}
|
||
|
||
.engagement-modal .header {
|
||
padding: 20px 50px 10px 30px;
|
||
position: relative;
|
||
}
|
||
|
||
.engagement-modal .title {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
color: #333333;
|
||
}
|
||
|
||
.engagement-modal .title:hover {
|
||
text-decoration: none;
|
||
}
|
||
|
||
.engagement-modal .close {
|
||
font-size: 18px;
|
||
position: absolute;
|
||
top: 18px;
|
||
right: 20px;
|
||
width: 32px;
|
||
height: 32px;
|
||
background: none;
|
||
border: none;
|
||
opacity: 0.8;
|
||
font-weight: bold;
|
||
text-shadow: 0 1px 0 #fff;
|
||
}
|
||
|
||
.engagement-modal .close:hover {
|
||
background-color: rgba(146, 148, 151, 0.2);
|
||
color: #000;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.engagement-modal .close:after {
|
||
content: '\2715';
|
||
}
|
||
|
||
.engagement-modal .content {
|
||
padding: 0 30px 20px;
|
||
width: min(450px, 90vw);
|
||
height: min(450px, 90vw);
|
||
scrollbar-width: thin;
|
||
overflow: auto;
|
||
overscroll-behavior: contain;
|
||
}
|
||
|
||
.engagement-modal .loading-screen,
|
||
.engagement-modal .content .center-screen {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 100%;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.engagement-modal .content .center-screen a {
|
||
color: var(--acc-ffffff-blue-1);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.engagement-modal .loading-screen i {
|
||
font-size: 24px;
|
||
}
|
||
|
||
.engagement-modal .media-left,
|
||
.engagement-modal .media-right {
|
||
display: table-cell;
|
||
vertical-align: top;
|
||
}
|
||
|
||
.engagement-modal .media-left {
|
||
padding-right: 10px;
|
||
}
|
||
|
||
.engagement-modal .media-right {
|
||
padding-left: 10px;
|
||
}
|
||
|
||
.engagement-modal .media a {
|
||
color: black;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.engagement-modal .avatar {
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.engagement-modal .footer {
|
||
margin: 20px 0 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: unset !important;
|
||
border-top: none !important;
|
||
}
|
||
|
||
.engagement-modal .footer .btn {
|
||
border: 1px solid transparent;
|
||
}
|
||
|
||
.engagement-modal .footer .btn-primary {
|
||
color: #fff;
|
||
border-color: #2e6da4;
|
||
}
|
||
|
||
.engagement-modal .footer button {
|
||
background-color: var(--acc-ffffff-blue-2);
|
||
padding: 6px 12px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.engagement-modal .footer button:hover {
|
||
filter: brightness(1.2);
|
||
}
|
||
|
||
@keyframes anim-spin {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
100% {
|
||
transform: rotate(359deg);
|
||
}
|
||
}
|
||
|
||
.engagement-modal .anim-spin {
|
||
display: inline-block;
|
||
animation: anim-spin 2s infinite linear;
|
||
}</style>
|
||
<script>document.addEventListener('alpine:init', () => {
|
||
Alpine.data('engagementModal', (nodeId) => ({
|
||
|
||
nodeId: null,
|
||
|
||
init() {
|
||
this.nodeId = nodeId;
|
||
},
|
||
|
||
open() {
|
||
this.updateStore();
|
||
this.$store.article.engagement.open = true;
|
||
if (this.$store.article.engagement.page === 1 && !this.$store.article.engagement.unauthorized) {
|
||
this.$store.article.engagement.initializing = true;
|
||
this.fetchEngagements();
|
||
}
|
||
},
|
||
|
||
close() {
|
||
if (this.$store.article.engagement.open) {
|
||
this.$store.article.engagement.open = false;
|
||
}
|
||
},
|
||
|
||
updateStore() {
|
||
if (this.nodeId !== this.$store.article.id) {
|
||
this.$store.article.engagement.reset();
|
||
this.$store.article.id = this.nodeId;
|
||
}
|
||
},
|
||
|
||
fetchEngagements() {
|
||
if (this.$store.article.engagement.loading || !this.$store.article.engagement.additional) {
|
||
return;
|
||
}
|
||
|
||
this.$store.article.engagement.loading = true;
|
||
this.$store.global.getFromService('/services/nodes/' + this.$store.article.id + '/engagements?page=' + this.$store.article.engagement.page)
|
||
.then(res => {
|
||
res.json().then(data => {
|
||
for (let user of data.engagements) {
|
||
this.$store.article.engagement.users.push(user);
|
||
}
|
||
|
||
this.$store.article.engagement.additional = data.additional;
|
||
this.$store.article.engagement.page++;
|
||
});
|
||
})
|
||
.catch(err => {
|
||
err.json().then(data => {
|
||
if (data.error?.code === 4011) {
|
||
this.$store.article.engagement.unauthorized = true;
|
||
} else {
|
||
this.$store.modal_engagement_error.open();
|
||
}
|
||
});
|
||
})
|
||
.finally(() => {
|
||
// Allow the loader to gracefully exit
|
||
setTimeout(() => {
|
||
this.$store.article.engagement.loading = false;
|
||
this.$store.article.engagement.initializing = false;
|
||
}, 200);
|
||
});
|
||
},
|
||
|
||
formatJobData(user) {
|
||
if (user.profile.jobTitle && user.profile.companyName) {
|
||
return user.profile.jobTitle + ', ' + user.profile.companyName;
|
||
}
|
||
|
||
if (user.profile.jobTitle) {
|
||
return user.profile.jobTitle;
|
||
}
|
||
|
||
if (user.profile.companyName) {
|
||
return user.profile.companyName;
|
||
}
|
||
|
||
return null;
|
||
},
|
||
|
||
isDataUnavailable() {
|
||
return !this.$store.article.engagement.initializing && !this.$store.article.engagement.users.length;
|
||
},
|
||
|
||
isFooterShowing() {
|
||
return !this.$store.article.engagement.initializing
|
||
&& this.$store.article.engagement.additional
|
||
&& this.$store.article.engagement.page > 1;
|
||
}
|
||
}));
|
||
});
|
||
</script>
|
||
|
||
<div class="alpine-overlay" x-cloak x-show="$store.modal_engagement_error._open">
|
||
<div id="modal_engagement_error"
|
||
class="alpine-modal"
|
||
role="dialog"
|
||
tabindex="-1"
|
||
x-show="$store.modal_engagement_error._open"
|
||
x-on:click.self="$store.modal_engagement_error.dismissible && $store.modal_engagement_error.close()"
|
||
x-cloak
|
||
x-transition
|
||
>
|
||
<div class="dz-style modal-inner centered relative">
|
||
<button x-show="$store.modal_engagement_error.closeable"
|
||
class="btn-close"
|
||
x-on:click="$store.modal_engagement_error.close()"
|
||
aria-label="Close">
|
||
</button>
|
||
|
||
<div x-show="$store.modal_engagement_error.title" class="modal-header p-sm mt-sm mb-md">
|
||
<div class="title " x-text="$store.modal_engagement_error.title"></div>
|
||
</div>
|
||
|
||
<div class="modal-content py-md px-lg" x-bind:class="{ 'has-top-border': $store.modal_engagement_error.title }">
|
||
<p x-show="$store.modal_engagement_error.bodyText" class="my-none" x-text="$store.modal_engagement_error.bodyText"></p>
|
||
<p>The likes didn't load as expected. Please refresh the page and try again.</p>
|
||
</div>
|
||
|
||
<div x-show="$store.modal_engagement_error.options.length" class="modal-footer p-sm">
|
||
<template x-for="option in $store.modal_engagement_error.options">
|
||
<button x-show="option.canDisplay" x-text="option.text"
|
||
type="button"
|
||
x-bind:id="'button_modal_engagement_error_' + option.index"
|
||
x-bind:class="option.classList"
|
||
x-on:click="option.onClick"
|
||
x-bind:disabled="option.isDisabled"
|
||
></button>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener("alpine:init", () => {
|
||
Alpine.store("modal_engagement_error", {
|
||
_open: false,
|
||
title: "Oops! Something Went Wrong",
|
||
bodyText: null,
|
||
options: [{"action":"dismiss","text":"Close"}],
|
||
closeable: true,
|
||
dismissible: true,
|
||
open(data) {
|
||
if (data) {
|
||
if (data.title) {
|
||
this.title = data.title;
|
||
}
|
||
if (data.bodyText) {
|
||
this.bodyText = data.bodyText;
|
||
}
|
||
if (data.options) {
|
||
this.options = data.options;
|
||
}
|
||
if (data.dismissAfterMs) {
|
||
setTimeout(() => this._open = false, data.dismissAfterMs);
|
||
}
|
||
}
|
||
this.updateOptions();
|
||
this._open = true;
|
||
},
|
||
close() {
|
||
// Manually click the buttons in which should run on dismiss.
|
||
// This is to keep the context. Calling this[option.action]() will not work.
|
||
for (let option of this.options) {
|
||
if (option.runOnDismiss) {
|
||
const element = document.querySelector('#button_modal_engagement_error_' + option.index);
|
||
element.click();
|
||
}
|
||
}
|
||
this._open = false;
|
||
},
|
||
updateOptions() {
|
||
const btnStyle = this.options.length === 2 ? ' btn-default' : '';
|
||
this.options = this.options.map((o, idx) => ({
|
||
...o,
|
||
index: idx,
|
||
classList: o.classList ? o.classList : (idx === 0 ? "btn btn-primary hov-brighten" : "btn hov-underline" + btnStyle),
|
||
onClick: function() {
|
||
if (o.action !== "dismiss") {
|
||
this[o.action]();
|
||
}
|
||
this.$store["modal_engagement_error"].close();
|
||
},
|
||
isDisabled: function() {
|
||
return Object.hasOwn(o, 'disabled') && this[o.disabled]();
|
||
},
|
||
canDisplay: function() {
|
||
return !Object.hasOwn(o, 'condition') || this[o.condition]();
|
||
}
|
||
}));
|
||
},
|
||
init() {
|
||
this.updateOptions();
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/footer/styles.css">
|
||
|
||
<div id="ftl-footer">
|
||
<div class="container-fluid footerOuter" style="padding-bottom: 90px;">
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<div class="container">
|
||
<div class="row footer">
|
||
<div class="col-md-12 footerWidget">
|
||
<div class="row footerContainer footer">
|
||
<div class="left col-xs-12 col-sm-7">
|
||
<div class="col-xs-12 social-media-icons footer-mobile">
|
||
<ul class="icons-only">
|
||
<li class="rss-icon" id="rss-footer-1">
|
||
<a href="/pages/feeds" target="_blank" rel="noreferrer noopener">
|
||
<svg role="img" viewBox="0 0 24 24" class="w-4 h-4 mt-1.75 fill-current" aria-label="Follow our RSS feeds">
|
||
<title>RSS</title>
|
||
<path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li class="twitter-icon">
|
||
<a href="https://twitter.com/DZoneInc" target="_blank" rel="noreferrer noopener">
|
||
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on X">
|
||
<title>X</title>
|
||
<path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li class="facebook-icon">
|
||
<a href="https://www.facebook.com/DZoneInc" target="_blank" rel="noreferrer noopener">
|
||
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on Facebook">
|
||
<title>Facebook</title>
|
||
<path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li class="linkedin-icon">
|
||
<a href="https://www.linkedin.com/company/dzone/" target="_blank"
|
||
rel="noreferrer noopener">
|
||
<svg viewBox="0 0 24 25" fill="none" aria-label="Follow us on LinkedIn">
|
||
<path d="M6.20062 21.2143H1.84688V7.194H6.20062V21.2143ZM4.02141 5.2815C2.62922 5.2815 1.5 4.12838 1.5 2.73619C1.5 2.06747 1.76565 1.42614 2.2385 0.953285C2.71136 0.48043 3.35269 0.214783 4.02141 0.214783C4.69012 0.214783 5.33145 0.48043 5.80431 0.953285C6.27716 1.42614 6.54281 2.06747 6.54281 2.73619C6.54281 4.12838 5.413 5.2815 4.02141 5.2815ZM22.4953 21.2143H18.1509V14.3893C18.1509 12.7628 18.1181 10.6768 15.8873 10.6768C13.6237 10.6768 13.2769 12.444 13.2769 14.2721V21.2143H8.92781V7.194H13.1034V9.1065H13.1644C13.7456 8.00494 15.1655 6.84244 17.2838 6.84244C21.69 6.84244 22.5 9.744 22.5 13.5128V21.2143H22.4953Z" fill="currentColor"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="top-section col-xs-12">
|
||
<div class="col-xs-12 col-sm-6">
|
||
<p class="section-header">ABOUT US</p>
|
||
<ul class="link-group">
|
||
<li><a href="/pages/about" rel="noreferrer noopener">About DZone</a></li>
|
||
<li><a href="/cdn-cgi/l/email-protection#14676164647b666054706e7b7a713a777b79" rel="noreferrer noopener">Support and feedback</a></li>
|
||
<li><a href="/pages/dzone-community-research">Community research</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="col-xs-12 col-sm-6">
|
||
<p class="section-header">ADVERTISE</p>
|
||
<ul class="link-group">
|
||
<li><a href="https://advertise.dzone.com" target="_blank" rel="noreferrer noopener">Advertise with DZone</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bottom-section col-xs-12">
|
||
<div class="col-xs-12 col-sm-6">
|
||
<p class="section-header">CONTRIBUTE ON DZONE</p>
|
||
<ul class="bottom-top-list link-group">
|
||
<li><a href="/articles/dzones-article-submission-guidelines">Article Submission Guidelines</a></li>
|
||
<li><a href="/pages/contribute" rel="noreferrer noopener">Become a Contributor</a></li>
|
||
<li><a href="/pages/core" rel="noreferrer noopener">Core Program</a></li>
|
||
<li><a href="/writers-zone" rel="noreferrer noopener">Visit the Writers' Zone</a></li>
|
||
</ul>
|
||
|
||
<p class="section-header">LEGAL</p>
|
||
<ul class="link-group">
|
||
<li><a href="https://technologyadvice.com/terms-conditions/" target="_blank" rel="noreferrer noopener">Terms of Service</a></li>
|
||
<li><a href="https://technologyadvice.com/privacy-policy/" target="_blank" rel="noreferrer noopener">Privacy Policy</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="col-xs-12 col-sm-6">
|
||
<p class="section-header">CONTACT US</p>
|
||
<ul class="link-group">
|
||
<li>3343 Perimeter Hill Drive</li>
|
||
<li>Suite 215</li>
|
||
<li>Nashville, TN 37211</li>
|
||
<li><a href="/cdn-cgi/l/email-protection#f1828481819e8385b1958b9e9f94df929e9c" rel="noreferrer noopener"><span class="__cf_email__" data-cfemail="d7a4a2a7a7b8a5a397b3adb8b9b2f9b4b8ba">[email protected]</span></a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="right col-xs-12 col-sm-5">
|
||
|
||
<p class="connect-text">Let's be friends:</p>
|
||
<div class="col-xs-12 social-media-icons footer-wide">
|
||
<ul class="icons-only">
|
||
<li class="rss-icon" id="rss-footer-1">
|
||
<a href="/pages/feeds" target="_blank" rel="noreferrer noopener">
|
||
<svg role="img" viewBox="0 0 24 24" aria-label="Follow our RSS feeds">
|
||
<title>RSS</title>
|
||
<path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li class="twitter-icon">
|
||
<a href="https://twitter.com/DZoneInc" target="_blank" rel="noreferrer noopener">
|
||
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on X">
|
||
<title>X</title>
|
||
<path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li class="facebook-icon">
|
||
<a href="https://www.facebook.com/DZoneInc" target="_blank" rel="noreferrer noopener">
|
||
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on Facebook">
|
||
<title>Facebook</title>
|
||
<path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li class="linkedin-icon">
|
||
<a href="https://www.linkedin.com/company/dzone/" target="_blank"
|
||
rel="noreferrer noopener">
|
||
<svg viewBox="0 0 24 25" fill="none" aria-label="Follow us on LinkedIn">
|
||
<path d="M6.20062 21.2143H1.84688V7.194H6.20062V21.2143ZM4.02141 5.2815C2.62922 5.2815 1.5 4.12838 1.5 2.73619C1.5 2.06747 1.76565 1.42614 2.2385 0.953285C2.71136 0.48043 3.35269 0.214783 4.02141 0.214783C4.69012 0.214783 5.33145 0.48043 5.80431 0.953285C6.27716 1.42614 6.54281 2.06747 6.54281 2.73619C6.54281 4.12838 5.413 5.2815 4.02141 5.2815ZM22.4953 21.2143H18.1509V14.3893C18.1509 12.7628 18.1181 10.6768 15.8873 10.6768C13.6237 10.6768 13.2769 12.444 13.2769 14.2721V21.2143H8.92781V7.194H13.1034V9.1065H13.1644C13.7456 8.00494 15.1655 6.84244 17.2838 6.84244C21.69 6.84244 22.5 9.744 22.5 13.5128V21.2143H22.4953Z" fill="currentColor"></path>
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script>
|
||
const articleId = 3545196;
|
||
const likes = 57;
|
||
const assetDomain = 'https://dz2cdn1.dzone.com';
|
||
const codemirrorVars = {
|
||
modeURI: 'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/mode/',
|
||
requiredScripts: [
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/lib/codemirror.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/addon/mode/overlay.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/addon/mode/multiplex.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/mode/meta.js'
|
||
]
|
||
};
|
||
|
||
const gptTags = {
|
||
'zone': 'Microservices',
|
||
'topicTag': 'Chaos Monkey,Chaos engineering,Kubernetes,spring boot,microservices',
|
||
'company': '',
|
||
'siteSection': 'Zones',
|
||
'articleCategory': 'analysis',
|
||
'nodeID': '3545196',
|
||
'authorID': '5292482',
|
||
'publishYear': '2025',
|
||
'publishMonth': '04',
|
||
'jobRole': '',
|
||
'companySize': '',
|
||
'env': 'prod'
|
||
};
|
||
|
||
const minCommentChar = 10;
|
||
</script>
|
||
<script async>const width = window.innerWidth;
|
||
|
||
const metadata = {
|
||
'top': {
|
||
'position': 'top',
|
||
'slot': 'dz2_article_billboard_new',
|
||
},
|
||
'sponsorLogo': {
|
||
'position': 'zoneHomepage',
|
||
'slot': 'dz2_homepage_sponsor_logo',
|
||
'refreshable': false
|
||
},
|
||
'sidebar1': {
|
||
'position': 'sidebar',
|
||
'slot': 'dz2_article_halfpage_new',
|
||
'minWidthToShow': 1024
|
||
},
|
||
'topBumper': {
|
||
'position': 'top',
|
||
'slot': 'dz2_bumper_text_ad',
|
||
'minWidthToShow': 1024
|
||
},
|
||
'bottomBumper': {
|
||
'position': 'bottom',
|
||
'slot': 'dz2_bumper_text_ad',
|
||
'minWidthToShow': 1024
|
||
},
|
||
'bottom': {
|
||
'position': 'bottom',
|
||
'slot': 'dz2_article_bottom',
|
||
},
|
||
'bottomStickyFooter': {
|
||
'position': 'sticky',
|
||
'slot': 'dz2_sticky_footer_leaderboard',
|
||
},
|
||
'partner': {
|
||
'slot': 'dz2_partner_resource_link',
|
||
},
|
||
'branded': {
|
||
'slot': 'dz2_branded_content',
|
||
'refreshable': false
|
||
},
|
||
'topicBillboard': {
|
||
'position': ['top', 'zoneHomepage'],
|
||
'slot': 'dz2_topic_billboard',
|
||
},
|
||
'listPageSidebar': {
|
||
'position': 'sidebar',
|
||
'slot': 'dz2_list_page_sidebar',
|
||
'minWidthToShow': 1024
|
||
},
|
||
'topListPageLeaderboard2': {
|
||
'position': ['top', 'zoneList'],
|
||
'slot': 'dz2_list_page_leaderboard_2',
|
||
},
|
||
'bottomListPageLeaderboard2': {
|
||
'position': ['bottom', 'zoneList'],
|
||
'slot': 'dz2_list_page_leaderboard_2',
|
||
},
|
||
'homepageLeaderboard': {
|
||
'position': 'top',
|
||
'slot': 'dz2_homepage_leaderboard',
|
||
},
|
||
'homepageLeaderboard2': {
|
||
'position': 'bottom',
|
||
'slot': 'dz2_homepage_leaderboard_2',
|
||
},
|
||
'skybox': {
|
||
'position': 'above nav',
|
||
'slot': 'dz_skybox',
|
||
'refreshable': false
|
||
},
|
||
'inline': {
|
||
'position': 'inline',
|
||
'slot': 'dz2_inline-article-display',
|
||
}
|
||
};
|
||
|
||
var campaign = new URLSearchParams(window.location.search).get("adTargeting_campaign");
|
||
|
||
window.googletag = window.googletag || { cmd: [] };
|
||
|
||
if (campaign) {
|
||
window.googletag.cmd.push(function() {
|
||
window.googletag.setConfig({ targeting: { campaign }});
|
||
});
|
||
}
|
||
|
||
let lastHeader = null;
|
||
|
||
const topContainer = document.querySelector('#top-bumper-container');
|
||
const bottomContainer = document.querySelector('#bottom-bumper-container');
|
||
|
||
function GAM_getPersistentValue(key) {
|
||
const stored = JSON.parse(localStorage.getItem(key));
|
||
|
||
if (!stored) {
|
||
return null;
|
||
}
|
||
|
||
const { value, expiration } = stored;
|
||
|
||
if (expiration && Date.now() >= expiration) {
|
||
localStorage.removeItem(key);
|
||
return null;
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
function GAM_setPersistentValue(key, value, expiration) {
|
||
// 5 minutes from now
|
||
if (!expiration) {
|
||
expiration = Date.now() + 300000;
|
||
}
|
||
|
||
const storedValue = JSON.stringify({
|
||
value: value,
|
||
expiration: expiration
|
||
});
|
||
|
||
localStorage.setItem(key, storedValue);
|
||
|
||
return value;
|
||
}
|
||
|
||
function GAM_synchronousRequest(params) {
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.open('GET', params.url, false);
|
||
xhr.setRequestHeader("Content-Type", "application/json");
|
||
|
||
if (typeof params.auth_header !== "undefined") {
|
||
xhr.setRequestHeader("Authorization", params.auth_header);
|
||
}
|
||
|
||
xhr.send(null);
|
||
if (xhr.status === 200) {
|
||
return xhr.responseText;
|
||
} else {
|
||
throw new Error('Request failed: ' + xhr.statusText);
|
||
}
|
||
}
|
||
|
||
function GAM_fetch_data(params) {
|
||
let stored_data = GAM_getPersistentValue(params.storage_key);
|
||
|
||
if (stored_data === null) {
|
||
try {
|
||
const response = GAM_synchronousRequest(params);
|
||
const data = JSON.parse(response);
|
||
|
||
// Store and expire after 30 minutes
|
||
return GAM_setPersistentValue(params.storage_key, data, Date.now() + 1800000);
|
||
} catch (error) {
|
||
console.error('Could not get ' + params.storage_key + ' data: ' + error);
|
||
return null;
|
||
}
|
||
} else {
|
||
return stored_data;
|
||
}
|
||
}
|
||
|
||
function GAM_setUpSixSenseTargeting() {
|
||
let meData = GAM_fetch_data({
|
||
url: "https://link.technologyadvice.com/_me",
|
||
storage_key: "ta_me_data"
|
||
});
|
||
let sixSenseData = GAM_fetch_data({
|
||
url: "https://epsilon.6sense.com/v3/company/details",
|
||
auth_header: "Token d20a1b0e892442270cbc4cb6801c0160d28af04c",
|
||
storage_key: "ta_6s_data"
|
||
});
|
||
|
||
function meDataIncludes(i) {
|
||
return meData.tags.includes(i);
|
||
}
|
||
|
||
if (typeof meData !== "undefined" && meData !== null) {
|
||
window.googletag.pubads().setTargeting("visitor_id", meData.vid);
|
||
window.googletag.pubads().setTargeting("user_agent", meData.user_agent);
|
||
|
||
var tags_mapping = {
|
||
"is_datacenter": ["site.is-datacenter"],
|
||
"is_suspected_bot": ["site.suspected-bad-bot", "site.bad-bot"],
|
||
"is_ta_user": ["site.is-ta-user"],
|
||
"is_crawler": ["site.user-agent-blocked"],
|
||
"is_ad_blocked": ["site.is-ad-blocked"],
|
||
};
|
||
|
||
for (var key in tags_mapping) {
|
||
if (tags_mapping[key].some(meDataIncludes)) {
|
||
window.googletag.pubads().setTargeting(key, 'true');
|
||
}
|
||
}
|
||
}
|
||
|
||
if (typeof sixSenseData !== "undefined" && sixSenseData !== null) {
|
||
var segment_ids = [];
|
||
if (sixSenseData.segments && sixSenseData.segments.ids && sixSenseData.segments.ids.length) {
|
||
sixSenseData.segments.ids.forEach(function (v) {
|
||
segment_ids.push(v.toString());
|
||
});
|
||
}
|
||
if (typeof segment_ids !== "undefined" && segment_ids.length > 0) {
|
||
window.googletag.pubads().setTargeting("segment_ids_6si", segment_ids);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (width >= 1024 && (topContainer || bottomContainer)) {
|
||
// Dynamically create bumper ad slots for non-mobile devices.
|
||
// Prevents ugly dividers being rendered on empty ad slots (mobile)
|
||
const topBumper = document.createElement('div');
|
||
topBumper.id = 'div-gpt-ad-1435246566686-3';
|
||
topBumper.classList.add('article-bumper', 'article-bumper-top', 'dz2_bumper_text_ad');
|
||
topBumper.setAttribute('data-gpt-slot', 'topBumper');
|
||
|
||
topContainer.appendChild(topBumper);
|
||
|
||
const bottomBumper = document.createElement('div');
|
||
bottomBumper.id = 'div-gpt-ad-1435246566686-4';
|
||
bottomBumper.classList.add('article-bumper', 'article-bumper-bottom', 'dz2_bumper_text_ad');
|
||
bottomBumper.setAttribute('data-gpt-slot', 'bottomBumper');
|
||
|
||
bottomContainer.appendChild(bottomBumper);
|
||
}
|
||
|
||
if (gptTags.zone) {
|
||
gptTags.zone = gptTags.zone.replaceAll(/[\s/]/g, '_')
|
||
.replaceAll(/[^a-zA-Z0-9_]/g, '')
|
||
.toLowerCase();
|
||
}
|
||
|
||
makeAds();
|
||
|
||
function handleSkybox() {
|
||
const skybox = document.querySelector('div.skybox');
|
||
if (skybox) {
|
||
document.body.classList.add('skybox-auto-collapse');
|
||
// observe classlist changes for offsetting sticky ads
|
||
const observer = new MutationObserver((mutations) => {
|
||
mutations.forEach((mutation) => {
|
||
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
||
let offset = 0;
|
||
if (!document.body.classList.contains('skybox-closed') && (
|
||
document.body.classList.contains('ccad-skybox-manualcollapse')
|
||
|| document.body.classList.contains('ccad-skybox-manualexpand')
|
||
)) {
|
||
offset = skybox.getBoundingClientRect().height;
|
||
}
|
||
let eligibleAds = [
|
||
{ element: document.querySelector('.content-right-images'), offset: 108 },
|
||
{ element: document.querySelector('.trending-sidebar'), offset: 88 },
|
||
{ element: document.querySelector('.trending'), offset: 88 }
|
||
];
|
||
for (let ad of eligibleAds) {
|
||
if (ad.element) {
|
||
ad.element.style.top = (ad.offset + offset) + 'px';
|
||
}
|
||
}
|
||
}
|
||
});
|
||
});
|
||
observer.observe(document.body, { attributes: true });
|
||
}
|
||
}
|
||
|
||
function isHeaderEligible(header) {
|
||
const range = document.createRange();
|
||
range.setStartAfter(lastHeader);
|
||
range.setEndBefore(header);
|
||
|
||
return range.toString().trim().length >= 600;
|
||
}
|
||
|
||
function placeInlineAds() {
|
||
const excludedContent = document.querySelectorAll('#ftl-article.branded-content, #ftl-article.sponsored');
|
||
|
||
if (excludedContent.length > 0) {
|
||
return;
|
||
}
|
||
|
||
const headers = Array.from(document.querySelectorAll('.content-html h2')).splice(1);
|
||
|
||
let globalIndex = 12;
|
||
|
||
for (let i = 0; i < headers.length; i++) {
|
||
if (!lastHeader || isHeaderEligible(headers[i])) {
|
||
const element = document.createElement('div');
|
||
element.id = 'div-gpt-ad-1435246566686-' + globalIndex;
|
||
element.classList.add('inline-display', 'dz2_inline-article-display');
|
||
element.setAttribute('data-gpt-slot', 'inline');
|
||
headers[i].before(element);
|
||
lastHeader = element;
|
||
globalIndex++;
|
||
}
|
||
}
|
||
}
|
||
|
||
function makeAds() {
|
||
handleSkybox();
|
||
placeInlineAds();
|
||
|
||
const script = document.createElement('script');
|
||
script.src = 'https://i6ByW9Zmz4ncxhHkb.ay.delivery/manager/i6ByW9Zmz4ncxhHkb';
|
||
script.type = 'text/javascript';
|
||
script.referrerPolicy = 'no-referrer-when-downgrade';
|
||
|
||
document.head.appendChild(script);
|
||
|
||
window.googletag.cmd.push(function() {
|
||
const containers = document.querySelectorAll('div[data-gpt-slot]');
|
||
|
||
for (let container of containers) {
|
||
const div = container.getAttribute('data-gpt-slot');
|
||
const meta = metadata[div];
|
||
|
||
if (meta.minWidthToShow && width < meta.minWidthToShow) {
|
||
continue;
|
||
}
|
||
|
||
window.googletag.pubads().setTargeting('hostname', window.location.hostname);
|
||
|
||
Object.keys(gptTags).forEach(function(key) {
|
||
window.googletag.pubads().setTargeting(key, gptTags[key]);
|
||
});
|
||
|
||
window.googletag.pubads().addEventListener('slotRenderEnded', (event) => {
|
||
window.requestAnimationFrame(() => {
|
||
var slotId = event.slot.getSlotElementId();
|
||
|
||
if (!slotId.includes('__ayManagerEnv__')) {
|
||
return;
|
||
}
|
||
|
||
var className = slotId.split('__ayManagerEnv__')[0];
|
||
var slotName = className.replace('dz2_', '').replace('dz_', '').replace(/_\d+$/, '');
|
||
var unitName = meta.slot.replace('dz2_', '').replace('dz_', '').replace(/_\d+$/, '');
|
||
|
||
if (slotName !== unitName) {
|
||
return;
|
||
}
|
||
|
||
var elem = document.getElementById(slotId);
|
||
|
||
if (!elem) {
|
||
console.warn('Ad element missing', slotId);
|
||
return;
|
||
}
|
||
|
||
// Ad unit did not fill, collapse slot
|
||
if (event.isEmpty && elem.parentElement) {
|
||
elem.parentElement.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
GAM_setUpSixSenseTargeting();
|
||
});
|
||
}
|
||
</script>
|
||
<script async>// InMobi Choice. Consent Manager Tag v3.0 (for TCF 2.2)
|
||
!function(){var e=window.location.hostname,t=document.createElement("script"),n=document.getElementsByTagName("script")[0],a="https://cmp.inmobi.com".concat("/choice/","vPn77x7pBG57Y","/","dzone.com","/choice.js?tag_version=V3"),p=0;t.async=!0,t.type="text/javascript",t.src=a,n.parentNode.insertBefore(t,n),function(){for(var e,t="__tcfapiLocator",n=[],a=window;a;){try{if(a.frames[t]){e=a;break}}catch(e){}if(a===window.top)break;a=a.parent}e||(!function e(){var n=a.document,p=!!a.frames[t];if(!p)if(n.body){var s=n.createElement("iframe");s.style.cssText="display:none",s.name=t,n.body.appendChild(s)}else setTimeout(e,5);return!p}(),a.__tcfapi=function(){var e,t=arguments;if(!t.length)return n;if("setGdprApplies"===t[0])t.length>3&&2===t[2]&&"boolean"==typeof t[3]&&(e=t[3],"function"==typeof t[2]&&t[2]("set",!0));else if("ping"===t[0]){var a={gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"};"function"==typeof t[2]&&t[2](a)}else"init"===t[0]&&"object"==typeof t[3]&&(t[3]=Object.assign(t[3],{tag_version:"V3"})),n.push(t)},a.addEventListener("message",(function(e){var t="string"==typeof e.data,n={};try{n=t?JSON.parse(e.data):e.data}catch(e){}var a=n.__tcfapiCall;a&&window.__tcfapi(a.command,a.version,(function(n,p){var s={__tcfapiReturn:{returnValue:n,success:p,callId:a.callId}};t&&(s=JSON.stringify(s)),e&&e.source&&e.source.postMessage&&e.source.postMessage(s,"*")}),a.parameter)}),!1))}(),function(){const e=["2:tcfeuv2","6:uspv1","7:usnatv1","8:usca","9:usvav1","10:uscov1","11:usutv1","12:usctv1"];window.__gpp_addFrame=function(e){if(!window.frames[e])if(document.body){var t=document.createElement("iframe");t.style.cssText="display:none",t.name=e,document.body.appendChild(t)}else window.setTimeout(window.__gpp_addFrame,10,e)},window.__gpp_stub=function(){var t=arguments;if(__gpp.queue=__gpp.queue||[],__gpp.events=__gpp.events||[],!t.length||1==t.length&&"queue"==t[0])return __gpp.queue;if(1==t.length&&"events"==t[0])return __gpp.events;var n=t[0],a=t.length>1?t[1]:null,p=t.length>2?t[2]:null;if("ping"===n)a({gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}},!0);else if("addEventListener"===n){"lastId"in __gpp||(__gpp.lastId=0),__gpp.lastId++;var s=__gpp.lastId;__gpp.events.push({id:s,callback:a,parameter:p}),a({eventName:"listenerRegistered",listenerId:s,data:!0,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}}},!0)}else if("removeEventListener"===n){for(var i=!1,o=0;o<__gpp.events.length;o++)if(__gpp.events[o].id==p){__gpp.events.splice(o,1),i=!0;break}a({eventName:"listenerRemoved",listenerId:p,data:i,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}}},!0)}else"hasSection"===n?a(!1,!0):"getSection"===n||"getField"===n?a(null,!0):__gpp.queue.push([].slice.apply(t))},window.__gpp_msghandler=function(e){var t="string"==typeof e.data;try{var n=t?JSON.parse(e.data):e.data}catch(e){n=null}if("object"==typeof n&&null!==n&&"__gppCall"in n){var a=n.__gppCall;window.__gpp(a.command,(function(n,p){var s={__gppReturn:{returnValue:n,success:p,callId:a.callId}};e.source.postMessage(t?JSON.stringify(s):s,"*")}),"parameter"in a?a.parameter:null,"version"in a?a.version:"1.1")}},"__gpp"in window&&"function"==typeof window.__gpp||(window.__gpp=window.__gpp_stub,window.addEventListener("message",window.__gpp_msghandler,!1),window.__gpp_addFrame("__gppLocator"))}();var s=function(){var e=arguments;typeof window.__uspapi!==s&&setTimeout((function(){void 0!==window.__uspapi&&window.__uspapi.apply(window.__uspapi,e)}),500)};if(void 0===window.__uspapi){window.__uspapi=s;var i=setInterval((function(){p++,window.__uspapi===s&&p<3?console.warn("USP is not accessible"):clearInterval(i)}),6e3)}}();
|
||
</script>
|
||
|
||
<script async>
|
||
(function(w, d, s, l, i) {
|
||
w[l] = w[l] || [];
|
||
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
|
||
var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
|
||
j.async = true;
|
||
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
|
||
f.parentNode.insertBefore(j,f);
|
||
})(window, document, 'script', 'dataLayer', 'GTM-K25QL22');
|
||
</script>
|
||
|
||
<script>
|
||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||
ga('create', 'UA-410289-1', 'auto');
|
||
ga('require', 'linkid', 'linkid.js');
|
||
ga('require', 'GTM-TSD9TZP');
|
||
ga('set', 'siteSpeedSampleRate', 25);
|
||
</script>
|
||
<script async src="https://www.google-analytics.com/analytics.js"></script>
|
||
<script async>var analytics = {
|
||
'dimension1': 'Microservices',
|
||
'dimension2': 'article/analysis',
|
||
'dimension3': '2025-04-11',
|
||
'dimension4': '0',
|
||
'dimension5': '',
|
||
'dimension7': 'Chaos Monkey, Chaos engineering, Kubernetes, spring boot, microservices',
|
||
'dimension8': 'prabhucseirtt',
|
||
'dimension9': 'undefined',
|
||
'dimension10': ''
|
||
};
|
||
|
||
if (window.ga) {
|
||
Object.keys(analytics).forEach(function(key) {
|
||
window.ga('set', key, analytics[key]);
|
||
});
|
||
|
||
window.ga('send', 'pageview');
|
||
}</script>
|
||
|
||
<script src="https://dz2cdn1.dzone.com/themes/dz20/lib/static/jquery/jquery.min.js"></script>
|
||
<script async src="https://dz2cdn1.dzone.com/themes/dz20/lib/static/bootstrap/bootstrap.min.js"></script>
|
||
|
||
<script>
|
||
function loadScript(src) {
|
||
return new Promise(function (resolve, reject) {
|
||
const s = document.createElement('script');
|
||
s.src = src;
|
||
s.onload = resolve;
|
||
s.onerror = reject;
|
||
document.head.appendChild(s);
|
||
});
|
||
}
|
||
|
||
function loadStyle(href) {
|
||
const link = document.createElement('link');
|
||
link.rel = 'stylesheet';
|
||
link.href = href;
|
||
document.head.appendChild(link);
|
||
}
|
||
|
||
function loadScriptsSync(deferred) {
|
||
var p = Promise.resolve();
|
||
for (var i = 0; i < deferred.length; i++) {
|
||
let script = deferred[i];
|
||
p = p.then(function() {
|
||
return loadScript(script);
|
||
});
|
||
}
|
||
return p;
|
||
}
|
||
|
||
function loadStyles() {
|
||
const deferred = [
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/lib/codemirror.css',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/comments/styles.css',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/css/froala_editor.pkgd.min.css',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/css/themes/gray.min.css',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/mini-profile.css'
|
||
];
|
||
|
||
for (var i = 0; i < deferred.length; i++) {
|
||
loadStyle(deferred[i]);
|
||
}
|
||
}
|
||
|
||
window.addEventListener('load', function(_event) {
|
||
loadStyles();
|
||
|
||
loadScriptsSync([
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/lazysizes.min.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/codeblocks.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/activity-bar.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/js/froala_editor.pkgd.min.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/froala/content.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/comments/content.js',
|
||
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/content.js'
|
||
]);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|