Commit 2ee2ff25 authored by Savorboard's avatar Savorboard

Deployed 93096128 with MkDocs version: 1.0.4

parent 52b2f6f0
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="description" content="Project documentation with Markdown.">
<link rel="canonical" href="http://cap.dotnetcore.xyz/about/contributing/">
<meta name="author" content="CAP Team">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../../img/favicon.ico">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.4.0">
<title>Contributing - CAP</title>
<link rel="stylesheet" href="../../assets/stylesheets/application.0284f74d.css">
<link rel="stylesheet" href="../../assets/stylesheets/application-palette.01803549.css">
<meta name="theme-color" content="#7e57c2">
<script src="../../assets/javascripts/modernizr.74668098.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono&display=fallback">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="../../assets/fonts/material-icons.css">
</head>
<body dir="ltr" data-md-color-primary="deep-purple" data-md-color-accent="indigo">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448" viewBox="0 0 416 448" id="__github"><path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19T128 352t-18.125-8.5-10.75-19T96 304t3.125-20.5 10.75-19T128 256t18.125 8.5 10.75 19T160 304zm160 0q0 10-3.125 20.5t-10.75 19T288 352t-18.125-8.5-10.75-19T256 304t3.125-20.5 10.75-19T288 256t18.125 8.5 10.75 19T320 304zm40 0q0-30-17.25-51T296 232q-10.25 0-48.75 5.25Q229.5 240 208 240t-39.25-2.75Q130.75 232 120 232q-29.5 0-46.75 21T56 304q0 22 8 38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0 37.25-1.75t35-7.375 30.5-15 20.25-25.75T360 304zm56-44q0 51.75-15.25 82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5T212 416q-19.5 0-35.5-.75t-36.875-3.125-38.125-7.5-34.25-12.875T37 371.5t-21.5-28.75Q0 312 0 260q0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25 30.875Q171.5 96 212 96q37 0 70 8 26.25-20.5 46.75-30.25T376 64q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34 99.5z"/></svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="#contributing" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="http://cap.dotnetcore.xyz" title="CAP" class="md-header-nav__button md-logo">
<img src="../../img/logo.svg" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
CAP
</span>
<span class="md-header-nav__topic">
Contributing
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://github.com/dotnetcore/CAP/" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#__github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
GitHub
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<nav class="md-tabs" data-md-component="tabs">
<div class="md-tabs__inner md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../.." title="Home" class="md-tabs__link md-tabs__link--active">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../../user-guide/en/getting-started/quick-start/" title="Documentation" class="md-tabs__link">
Documentation
</a>
</li>
<li class="md-tabs__item">
<a href="../../user-guide/zh/getting-started/quick-start/" title="文档(中文)" class="md-tabs__link">
文档(中文)
</a>
</li>
<li class="md-tabs__item">
<a href="../contact-us/" title="About" class="md-tabs__link">
About
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="http://cap.dotnetcore.xyz" title="CAP" class="md-nav__button md-logo">
<img src="../../img/logo.svg" width="48" height="48">
</a>
CAP
</label>
<div class="md-nav__source">
<a href="https://github.com/dotnetcore/CAP/" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#__github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
GitHub
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." title="Home" class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2" type="checkbox" id="nav-2">
<label class="md-nav__link" for="nav-2">
Documentation
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-2">
Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2-1" type="checkbox" id="nav-2-1">
<label class="md-nav__link" for="nav-2-1">
Getting Stared
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-2-1">
Getting Stared
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/en/getting-started/quick-start/" title="Quick Start" class="md-nav__link">
Quick Start
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/getting-started/introduction/" title="Introduction" class="md-nav__link">
Introduction
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/getting-started/contributing/" title="Contributing" class="md-nav__link">
Contributing
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2-2" type="checkbox" id="nav-2-2">
<label class="md-nav__link" for="nav-2-2">
CAP
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-2-2">
CAP
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/en/cap/configuration/" title="Configuration" class="md-nav__link">
Configuration
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/cap/messaging/" title="Messaging" class="md-nav__link">
Messaging
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/cap/sagas/" title="Sagas" class="md-nav__link">
Sagas
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/cap/serialization/" title="Serialization" class="md-nav__link">
Serialization
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/cap/transactions/" title="Transactions" class="md-nav__link">
Transactions
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/cap/idempotence/" title="Idempotence" class="md-nav__link">
Idempotence
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2-3" type="checkbox" id="nav-2-3">
<label class="md-nav__link" for="nav-2-3">
Transports
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-2-3">
Transports
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/en/transports/general/" title="General" class="md-nav__link">
General
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/transports/rabbitmq/" title="RabbitMQ" class="md-nav__link">
RabbitMQ
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/transports/kafka/" title="Apache Kafka®" class="md-nav__link">
Apache Kafka®
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/transports/azure-service-bus/" title="Azure Service Bus" class="md-nav__link">
Azure Service Bus
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/transports/in-memory-queue/" title="In-Memory Queue" class="md-nav__link">
In-Memory Queue
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2-4" type="checkbox" id="nav-2-4">
<label class="md-nav__link" for="nav-2-4">
Persistent
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-2-4">
Persistent
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/en/persistent/general/" title="General" class="md-nav__link">
General
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/persistent/sqlserver/" title="SQL Server" class="md-nav__link">
SQL Server
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/persistent/mysql/" title="MySQL" class="md-nav__link">
MySQL
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/persistent/postgresql/" title="PostgreSql" class="md-nav__link">
PostgreSql
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/persistent/mongodb/" title="MongoDB" class="md-nav__link">
MongoDB
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/persistent/in-memory-storage/" title="In-Memory" class="md-nav__link">
In-Memory
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2-5" type="checkbox" id="nav-2-5">
<label class="md-nav__link" for="nav-2-5">
Monitoring
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-2-5">
Monitoring
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/en/monitoring/dashboard/" title="Dashboard" class="md-nav__link">
Dashboard
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/monitoring/diagnostics/" title="Diagnostics" class="md-nav__link">
Diagnostics
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2-6" type="checkbox" id="nav-2-6">
<label class="md-nav__link" for="nav-2-6">
Samples
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-2-6">
Samples
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/en/samples/github/" title="Github" class="md-nav__link">
Github
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/samples/eshoponcontainers/" title="eShopOnContainers" class="md-nav__link">
eShopOnContainers
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/en/samples/faq/" title="FAQ" class="md-nav__link">
FAQ
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3" type="checkbox" id="nav-3">
<label class="md-nav__link" for="nav-3">
文档(中文)
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-3">
文档(中文)
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3-1" type="checkbox" id="nav-3-1">
<label class="md-nav__link" for="nav-3-1">
入门
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-3-1">
入门
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/zh/getting-started/quick-start/" title="快速开始" class="md-nav__link">
快速开始
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/getting-started/introduction/" title="介绍" class="md-nav__link">
介绍
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/getting-started/contributing/" title="贡献" class="md-nav__link">
贡献
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3-2" type="checkbox" id="nav-3-2">
<label class="md-nav__link" for="nav-3-2">
CAP
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-3-2">
CAP
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/zh/cap/configuration/" title="配置" class="md-nav__link">
配置
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/cap/messaging/" title="消息" class="md-nav__link">
消息
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/cap/sagas/" title="Sagas" class="md-nav__link">
Sagas
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/cap/serialization/" title="序列化" class="md-nav__link">
序列化
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/cap/transactions/" title="传输" class="md-nav__link">
传输
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/cap/idempotence/" title="幂等性" class="md-nav__link">
幂等性
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3-3" type="checkbox" id="nav-3-3">
<label class="md-nav__link" for="nav-3-3">
传输
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-3-3">
传输
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/zh/transports/general/" title="简介" class="md-nav__link">
简介
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/transports/rabbitmq/" title="RabbitMQ" class="md-nav__link">
RabbitMQ
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/transports/kafka/" title="Apache Kafka®" class="md-nav__link">
Apache Kafka®
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/transports/azure-service-bus/" title="Azure Service Bus" class="md-nav__link">
Azure Service Bus
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/transports/in-memory-queue/" title="In-Memory Queue" class="md-nav__link">
In-Memory Queue
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3-4" type="checkbox" id="nav-3-4">
<label class="md-nav__link" for="nav-3-4">
持久化
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-3-4">
持久化
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/zh/persistent/general/" title="简介" class="md-nav__link">
简介
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/persistent/sqlserver/" title="SQL Server" class="md-nav__link">
SQL Server
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/persistent/mysql/" title="MySQL" class="md-nav__link">
MySQL
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/persistent/postgresql/" title="PostgreSql" class="md-nav__link">
PostgreSql
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/persistent/mongodb/" title="MongoDB" class="md-nav__link">
MongoDB
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/persistent/in-memory-storage/" title="In-Memory" class="md-nav__link">
In-Memory
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3-5" type="checkbox" id="nav-3-5">
<label class="md-nav__link" for="nav-3-5">
监控
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-3-5">
监控
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/zh/monitoring/consul/" title="Consul" class="md-nav__link">
Consul
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/monitoring/dashboard/" title="Dashboard" class="md-nav__link">
Dashboard
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/monitoring/diagnostics/" title="Diagnostics" class="md-nav__link">
Diagnostics
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/monitoring/health-checks/" title="健康检查" class="md-nav__link">
健康检查
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/monitoring/metrics/" title="Metrics" class="md-nav__link">
Metrics
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3-6" type="checkbox" id="nav-3-6">
<label class="md-nav__link" for="nav-3-6">
示例
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="2">
<label class="md-nav__title" for="nav-3-6">
示例
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guide/zh/samples/github/" title="Github" class="md-nav__link">
Github
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/samples/eshoponcontainers/" title="eShopOnContainers" class="md-nav__link">
eShopOnContainers
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guide/zh/samples/faq/" title="FAQ" class="md-nav__link">
FAQ
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-4" type="checkbox" id="nav-4">
<label class="md-nav__link" for="nav-4">
About
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-4">
About
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../contact-us/" title="Contact Us" class="md-nav__link">
Contact Us
</a>
</li>
<li class="md-nav__item">
<a href="../release-notes/" title="Release Notes" class="md-nav__link">
Release Notes
</a>
</li>
<li class="md-nav__item">
<a href="../license/" title="License" class="md-nav__link">
License
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<a href="https://github.com/dotnetcore/CAP/edit/master/docs/about/contributing.md" title="Edit this page" class="md-icon md-content__icon">&#xE3C9;</a>
<h1 id="contributing">Contributing<a class="headerlink" href="#contributing" title="Permanent link">&para;</a></h1>
<p>Pull requests, issues and commentary welcome! No special process just create a request and get in touch either via gitter or create an issue.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2017 <a href="https://github.com/dotnetcore">.NET Core Community</a>, Maintained by the <a href="/about/contact-us/#cap-team">CAP Team</a>.
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
<div class="md-footer-social">
<link rel="stylesheet" href="../../assets/fonts/font-awesome.css">
<a href="https://github.com/dotnetcore/CAP" class="md-footer-social__link fa fa-github"></a>
<a href="https://twitter.com/ncc_community" class="md-footer-social__link fa fa-twitter"></a>
<a href="https://weibo.com/dotnetcore" class="md-footer-social__link fa fa-weibo"></a>
</div>
</div>
</div>
</footer>
</div>
<script src="../../assets/javascripts/application.245445c6.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:"../.."}})</script>
</body>
</html>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,287 +2,287 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://cap.dotnetcore.xyz/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/getting-started/quick-start/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/getting-started/introduction/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/getting-started/contributing/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/cap/configuration/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/cap/messaging/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/cap/sagas/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/cap/serialization/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/cap/transactions/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/cap/idempotence/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/transports/general/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/transports/rabbitmq/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/transports/kafka/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/transports/azure-service-bus/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/transports/in-memory-queue/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/persistent/general/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/persistent/sqlserver/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/persistent/mysql/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/persistent/postgresql/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/persistent/mongodb/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/persistent/in-memory-storage/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/monitoring/dashboard/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/monitoring/diagnostics/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/samples/github/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/samples/eshoponcontainers/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/en/samples/faq/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/getting-started/quick-start/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/getting-started/introduction/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/getting-started/contributing/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/cap/configuration/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/cap/messaging/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/cap/sagas/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/cap/serialization/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/cap/transactions/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/cap/idempotence/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/transports/general/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/transports/rabbitmq/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/transports/kafka/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/transports/azure-service-bus/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/transports/in-memory-queue/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/persistent/general/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/persistent/sqlserver/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/persistent/mysql/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/persistent/postgresql/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/persistent/mongodb/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/persistent/in-memory-storage/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/monitoring/consul/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/monitoring/dashboard/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/monitoring/diagnostics/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/monitoring/health-checks/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/monitoring/metrics/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/samples/github/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/samples/eshoponcontainers/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/user-guide/zh/samples/faq/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/about/contact-us/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/about/release-notes/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>http://cap.dotnetcore.xyz/about/license/</loc>
<lastmod>2019-07-13</lastmod>
<lastmod>2019-07-15</lastmod>
<changefreq>daily</changefreq>
</url>
</urlset>
\ No newline at end of file
No preview for this file type
......@@ -502,8 +502,8 @@
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#_1" title="交付保证" class="md-nav__link">
交付保证
<a href="#delivery-guarantees1" title="Delivery guarantees1" class="md-nav__link">
Delivery guarantees1
</a>
<nav class="md-nav">
......@@ -524,8 +524,8 @@
</li>
<li class="md-nav__item">
<a href="#_2" title="什么是 “工作事务” ?" class="md-nav__link">
什么是 “工作事务” ?
<a href="#what-is-a-work-transaction" title="What is a "work transaction"?" class="md-nav__link">
What is a "work transaction"?
</a>
</li>
......@@ -536,30 +536,30 @@
</li>
<li class="md-nav__item">
<a href="#cap" title="CAP 中的幂等性" class="md-nav__link">
CAP 中的幂等性
<a href="#idempotence-at-cap" title="Idempotence at CAP" class="md-nav__link">
Idempotence at CAP
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_3" title="为什么没有实现幂等?" class="md-nav__link">
为什么没有实现幂等?
<a href="#why-are-we-not-providingachieving-idempotency" title="Why are we not providing(achieving) idempotency ?" class="md-nav__link">
Why are we not providing(achieving) idempotency ?
</a>
</li>
<li class="md-nav__item">
<a href="#_4" title="以自然的方式处理幂等消息" class="md-nav__link">
以自然的方式处理幂等消息
<a href="#naturally-idempotent-message-processing" title="Naturally idempotent message processing" class="md-nav__link">
Naturally idempotent message processing
</a>
</li>
<li class="md-nav__item">
<a href="#_5" title="显式处理幂等消息" class="md-nav__link">
显式处理幂等消息
<a href="#explicitly-handling-redeliveries" title="Explicitly handling redeliveries" class="md-nav__link">
Explicitly handling redeliveries
</a>
</li>
......@@ -1463,8 +1463,8 @@
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#_1" title="交付保证" class="md-nav__link">
交付保证
<a href="#delivery-guarantees1" title="Delivery guarantees1" class="md-nav__link">
Delivery guarantees1
</a>
<nav class="md-nav">
......@@ -1485,8 +1485,8 @@
</li>
<li class="md-nav__item">
<a href="#_2" title="什么是 “工作事务” ?" class="md-nav__link">
什么是 “工作事务” ?
<a href="#what-is-a-work-transaction" title="What is a "work transaction"?" class="md-nav__link">
What is a "work transaction"?
</a>
</li>
......@@ -1497,30 +1497,30 @@
</li>
<li class="md-nav__item">
<a href="#cap" title="CAP 中的幂等性" class="md-nav__link">
CAP 中的幂等性
<a href="#idempotence-at-cap" title="Idempotence at CAP" class="md-nav__link">
Idempotence at CAP
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_3" title="为什么没有实现幂等?" class="md-nav__link">
为什么没有实现幂等?
<a href="#why-are-we-not-providingachieving-idempotency" title="Why are we not providing(achieving) idempotency ?" class="md-nav__link">
Why are we not providing(achieving) idempotency ?
</a>
</li>
<li class="md-nav__item">
<a href="#_4" title="以自然的方式处理幂等消息" class="md-nav__link">
以自然的方式处理幂等消息
<a href="#naturally-idempotent-message-processing" title="Naturally idempotent message processing" class="md-nav__link">
Naturally idempotent message processing
</a>
</li>
<li class="md-nav__item">
<a href="#_5" title="显式处理幂等消息" class="md-nav__link">
显式处理幂等消息
<a href="#explicitly-handling-redeliveries" title="Explicitly handling redeliveries" class="md-nav__link">
Explicitly handling redeliveries
</a>
</li>
......@@ -1550,75 +1550,91 @@
<h1 id="idempotence">Idempotence<a class="headerlink" href="#idempotence" title="Permanent link">&para;</a></h1>
<p>幂等性(你可以在<a href="https://en.wikipedia.org/wiki/Idempotence">Wikipedia</a>读到关于幂等性的定义),当我们谈论幂等时,一般是指可以重复处理传毒的消息,而不是产生意外的结果。</p>
<h2 id="_1">交付保证<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<p>在说幂等性之前,我们先来说下关于消费端的消息交付。</p>
<p>由于CAP不是使用的 MS DTC 或其他类型的2PC分布式事务机制,所以存在至少消息严格交付一次的问题,具体的说在基于消息的系统中,存在一下三种可能:</p>
<p>Imdempotence (which you may read a formal definition of on <a href="https://en.wikipedia.org/wiki/Idempotence">Wikipedia</a>, when we are talking about messaging, is when a message redelivery can be handled without ending up in an unintended state.</p>
<h2 id="delivery-guarantees1">Delivery guarantees<sup id="fnref:1"><a class="footnote-ref" href="#fn:1" rel="footnote">1</a></sup><a class="headerlink" href="#delivery-guarantees1" title="Permanent link">&para;</a></h2>
<p>Before we talk about idempotency, let's talk about the delivery of messages on the consumer side.</p>
<p>Since CAP is not a used MS DTC or other type of 2PC distributed transaction mechanism, there is a problem that at least the message is strictly delivered once. Specifically, in a message-based system, there are three possibilities:</p>
<ul>
<li>Exactly Once(*) (仅有一次)</li>
<li>At Most Once (最多一次)</li>
<li>At Least Once (最少一次)</li>
<li>Exactly Once(*) </li>
<li>At Most Once </li>
<li>At Least Once </li>
</ul>
<p>带 * 号表示在实际场景中,很难达到。</p>
<p>Exactly once has a (*) next to it, because in the general case, it is simply not possible.</p>
<h3 id="at-most-once">At Most Once<a class="headerlink" href="#at-most-once" title="Permanent link">&para;</a></h3>
<p>最多一次交付保证,涵盖了保证一次或根本不接收所有消息的情况。</p>
<p>这种类型的传递保证可能来自你的消息系统,你的代码按以下顺序执行其操作:</p>
<div class="codehilite"><pre><span></span>1. 从队列移除消息
2. 开始一个工作事务
3. 处理消息 ( 你的代码 )
4. 是否成功 ?
<p>The At Most Once delivery guarantee covers the case when you are guaranteed to receive all messages either once, or maybe not at all.</p>
<p>This type of delivery guarantee can arise from your messaging system and your code performing its actions in the following order:</p>
<div class="codehilite"><pre><span></span>1. Remove message from queue
2. Start work transaction
3. Handle message (your code)
4. Success?
Yes:
1. 提交工作事务
1. Commit work transaction
No:
1. 回滚工作事务
2. 将消息发回到队列。
1. Roll back work transaction
2. Put message back into the queue
</pre></div>
<p>正常情况下,他们工作的很好,工作事务将被提交。</p>
<p>然而,有些时候并不能总是成功,比如在 1 之后出现异常,或者是你在将消息放回到队列中出现网络问题由或者宕机重启等情况。</p>
<p>使用这个协议,你将冒着丢失消息的风险,如果可以接受,那就没有关系。</p>
<p>In the sunshine scenario, this is all well and good – your messages will be received, and work transactions will be committed, and you will be happy.</p>
<p>However, the sun does not always shine, and stuff tends to fail – especially if you do enough stuff. Consider e.g. what would happen if anything fails after having performed step (1), and then – when you try to execute step (4)/(2) (i.e. put the message back into the queue) – the network was temporarily unavailable, or the message broker restarted, or the host machine decided to reboot because it had installed an update.</p>
<p>This can be OK if it's what you want, but most things in CAP revolve around the concept of DURABLE messages, i.e. messages whose contents is just as important as the data in your database.</p>
<h3 id="at-least-once">At Least Once<a class="headerlink" href="#at-least-once" title="Permanent link">&para;</a></h3>
<p>这个交付保证包含你收到至少一次的消息,当出现故障时,可能会收到多次消息。</p>
<p>它需要稍微改变我们执行步骤的顺序,它要求消息队列系统支持事务或ACK机制,比如传统的 begin-commit-rollback 协议(MSMQ是这样),或者是 receive-ack-nack 协议(RabbitMQ,Azure Service Bus等是这样的)。</p>
<p>大致步骤如下:</p>
<div class="codehilite"><pre><span></span>1. 抢占队列中的消息。
2. 开始一个工作事务
3. 处理消息 ( 你的代码 )
4. 是否成功 ?
<p>This delivery guarantee covers the case when you are guaranteed to receive all messages either once, or maybe more times if something has failed.</p>
<p>It requires a slight change to the order we are executing our steps in, and it requires that the message queue system supports transactions, either in the form of the traditional begin-commit-rollback protocol (MSMQ does this), or in the form of a receive-ack-nack protocol (RabbitMQ, Azure Service Bus, etc. do this).</p>
<p>Check this out – if we do this:</p>
<div class="codehilite"><pre><span></span>1. Grab lease on message in queue
2. Start work transaction
3. Handle message (your code)
4. Success?
Yes:
1. 提交工作事务
2. 从队列删除消息
1. Commit work transaction
2. Delete message from queue
No:
1. 回滚工作事务
2. 从队列释放抢占的消息
1. Roll back work transaction
2. Release lease on message
</pre></div>
<p>当出现失败或者抢占消息超时的时候,我们总是能够再次接收到消息以保证我们工作事务提交成功。</p>
<h3 id="_2">什么是 “工作事务” ?<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h3>
<p>上面所说的“工作事务”并不是特指关系型数据库中的事务,这里的工作事务是一个概念,也就是说执行代码的原子性。</p>
<p>比如它可以是传统的RDMS事务,也或者是 MongoDB 事务或者是一个交易等。</p>
<p>在这里它代表一个执行单元,这个执行单元是一个概念性的事实以支持前面提到的仅交付一次的这种问题。</p>
<p>通常,不可能做到消息的事务和工作事务来形成原子性进行提交或者回滚。</p>
<h2 id="cap">CAP 中的幂等性<a class="headerlink" href="#cap" title="Permanent link">&para;</a></h2>
<p>在CAP中,我们采用的交付保证为 At Least Once。</p>
<p>由于我们具有临时存储介质(数据库表),也许可以做到 At Most Once, 但是为了严格保证消息不会丢失,我们没有提供相关功能或配置。</p>
<h3 id="_3">为什么没有实现幂等?<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h3>
<p>1、消息写入成功了,但是此时执行Consumer方法失败了</p>
<p>执行Consumer方法失败的原因有非常多,我如果不知道具体的场景盲目进行重试或者不进行重试都是不正确的选择。
举个例子:假如消费者为扣款服务,如果是执行扣款成功了,但是在写扣款日志的时候失败了,此时CAP会判断为消费者执行失败,进行重试。如果客户端自己没有保证幂等性,框架对其进行重试,这里势必会造成多次扣款出现严重后果。</p>
<p>2、执行Consumer方法成功了,但是又收到了同样的消息</p>
<p>此处场景也是可能存在的,假如开始的时候Consumer已经执行成功了,但是由于某种原因如 Broker 宕机恢复等,又收到了相同的消息,CAP 在收到Broker消息后会认为这个是一个新的消息,会对 Consumer再次执行,由于是新消息,此时 CAP 也是无法做到幂等的。</p>
<p>3、目前的数据存储模式无法做到幂等</p>
<p>由于CAP存消息的表对于成功消费的消息会于1个小时后删除,所以如果对于一些历史性消息无法做到幂等操作。 历史性指的是,假如 Broker由于某种原因维护了或者是人工处理的一些消息。</p>
<p>4、业界做法</p>
<p>许多基于事件驱动的框架都是要求 用户 来保证幂等性操作的,比如 ENode, RocketMQ 等等...</p>
<p>从实现的角度来说,CAP可以做一些比较不严格的幂等,但是严格的幂等无法做到的。</p>
<h3 id="_4">以自然的方式处理幂等消息<a class="headerlink" href="#_4" title="Permanent link">&para;</a></h3>
<p>通常情况下,保证消息被执行多次而不会产生意外结果是很自然的一种方式是采用操作对象自带的一些幂等功能。比如:</p>
<p>数据库提供的 <code class="codehilite">INSERT ON DUPLICATE KEY UPDATE</code> 或者是采取类型的程序判断行为。</p>
<h3 id="_5">显式处理幂等消息<a class="headerlink" href="#_5" title="Permanent link">&para;</a></h3>
<p>另外一种处理幂等性的方式就是在消息传递的过程中传递ID,然后由单独的消息跟踪器来处理。 </p>
<p>比如你使用具有事务数据存储的 IMessageTracker 来跟踪消息ID,你的代码可能看起来像这样:</p>
<p>and the "lease" we grabbed on the message in step (1) is associated with an appropriate timeout, then we are guaranteed that no matter how wrong things go, we will only actually remove the message from the queue (i.e. execute step (4)/(2)) if we have successfully committed our "work transaction".</p>
<h3 id="what-is-a-work-transaction">What is a "work transaction"?<a class="headerlink" href="#what-is-a-work-transaction" title="Permanent link">&para;</a></h3>
<p>It depends on what you're doing 😄 maybe it's a transaction in a relational database (which traditionally have pretty good support in this regard), maybe it's a transaction in a document database that happens to support transaction (like RavenDB or Postgres), or maybe it's a conceptual transaction in the form of whichever work you happen to carry out as a consequence of handling a message, e.g. update a bunch of documents in MongoDB, move some files around in the file system, or mutate some obscure in-mem data structure.</p>
<p>The fact that the "work transaction" is just a conceptual thing is what makes it impossible to support the aforementioned Exactly Once delivery guarantee – it's just not generally possible to commit or roll back a "work transaction" and a "queue transaction" (which is what we could call the protocol carried out with the message queue systems) atomically and consistently.</p>
<h2 id="idempotence-at-cap">Idempotence at CAP<a class="headerlink" href="#idempotence-at-cap" title="Permanent link">&para;</a></h2>
<p>In the CAP, the delivery guarantees we use is <strong>At Least Once</strong>.</p>
<p>Since we have a temporary storage medium (database table), we may be able to do At Most Once, but in order to strictly guarantee that the message will not be lost, we do not provide related functions or configurations.</p>
<h3 id="why-are-we-not-providingachieving-idempotency">Why are we not providing(achieving) idempotency ?<a class="headerlink" href="#why-are-we-not-providingachieving-idempotency" title="Permanent link">&para;</a></h3>
<ol>
<li>
<p>The message was successfully written, but the execution of the Consumer method failed. </p>
<p>There are a lot of reasons why the Consumer method fails. I don't know if the specific scene is blindly retrying or not retrying is an incorrect choice.
For example, if the consumer is debiting service, if the execution of the debit is successful, but fails to write the debit log, the CAP will judge that the consumer failed to execute and try again. If the client does not guarantee idempotency, the framework will retry it, which will inevitably lead to serious consequences for multiple debits.</p>
</li>
<li>
<p>The implementation of the Consumer method succeeded, but received the same message. </p>
<p>The scenario is also possible here. If the Consumer has been successfully executed at the beginning, but for some reason, such as the Broker recovery, and received the same message, the CAP will consider this a new after receiving the Broker message. The message will be executed again by the Consumer. Because it is a new message, the CAP cannot be idempotent at this time.</p>
</li>
<li>
<p>The current data storage mode can not be idempotent. </p>
<p>Since the table of the CAP message is deleted after 1 hour for the successfully consumed message, if the historical message cannot be idempotent. Historically, if the broker has maintained or manually processed some messages for some reason.</p>
</li>
<li>
<p>Industry practices.</p>
<p>Many event-driven frameworks require users to ensure idempotent operations, such as ENode, RocketMQ, etc...</p>
</li>
</ol>
<p>From an implementation point of view, CAP can do some less stringent idempotence, but strict idempotent cannot.</p>
<h3 id="naturally-idempotent-message-processing">Naturally idempotent message processing<a class="headerlink" href="#naturally-idempotent-message-processing" title="Permanent link">&para;</a></h3>
<p>Generally, the best way to deal with message redeliveries is to make the processing of each message naturally idempotent.</p>
<p>Natural idempotence arises when the processing of a message consists of calling an idempotent method on a domain object, like</p>
<div class="codehilite"><pre><span></span>obj.MarkAsDeleted();
</pre></div>
<p>or</p>
<div class="codehilite"><pre><span></span>obj.UpdatePeriod(message.NewPeriod);
</pre></div>
<p>You can use the <code class="codehilite">INSERT ON DUPLICATE KEY UPDATE</code> provided by the database to easily done.</p>
<h3 id="explicitly-handling-redeliveries">Explicitly handling redeliveries<a class="headerlink" href="#explicitly-handling-redeliveries" title="Permanent link">&para;</a></h3>
<p>Another way of making message processing idempotent, is to simply track IDs of processed messages explicitly, and then make your code handle a redelivery.</p>
<p>Assuming that you are keeping track of message IDs by using an <code class="codehilite">IMessageTracker</code> that uses the same transactional data store as the rest of your work, your code might look somewhat like this:</p>
<div class="codehilite"><pre><span></span><span class="k">readonly</span> <span class="n">IMessageTracker</span> <span class="n">_messageTracker</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">SomeMessageHandler</span><span class="p">(</span><span class="n">IMessageTracker</span> <span class="n">messageTracker</span><span class="p">)</span>
......@@ -1642,7 +1658,15 @@
<span class="p">}</span>
</pre></div>
<p>至于 <code class="codehilite">IMessageTracker</code> 的实现,可以使用诸如Redis或者数据库等存储消息Id和对应的处理状态。</p>
<p>As for the implementation of <code class="codehilite">IMessageTracker</code>, you can use a storage message Id such as Redis or a database and the corresponding processing state.</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>The chapter refers to the <a href="https://github.com/rebus-org/Rebus/wiki/Delivery-guarantees">Delivery guarantees</a> of rebus, which I think is described very good.&#160;<a class="footnote-backref" href="#fnref:1" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
......
......@@ -91,7 +91,7 @@
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="#_1" tabindex="1" class="md-skip">
<a href="#transaction" tabindex="1" class="md-skip">
Skip to content
</a>
......@@ -490,16 +490,38 @@
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#_2" title="分布式事务?" class="md-nav__link">
分布式事务?
<a href="#distributed-transactions" title="Distributed transactions?" class="md-nav__link">
Distributed transactions?
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_3" title="异步确保" class="md-nav__link">
异步确保
<a href="#eventual-consistency-and-compensation-1" title="Eventual Consistency and Compensation 1" class="md-nav__link">
Eventual Consistency and Compensation 1
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#a-case-for-eventual-consistency" title="A Case for Eventual Consistency" class="md-nav__link">
A Case for Eventual Consistency
</a>
</li>
<li class="md-nav__item">
<a href="#happy-scenario" title="Happy Scenario" class="md-nav__link">
Happy Scenario
</a>
</li>
<li class="md-nav__item">
<a href="#failure-scenarios" title="Failure Scenarios" class="md-nav__link">
Failure Scenarios
</a>
</li>
......@@ -509,6 +531,11 @@
</li>
</ul>
</nav>
</li>
......@@ -1415,16 +1442,38 @@
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#_2" title="分布式事务?" class="md-nav__link">
分布式事务?
<a href="#distributed-transactions" title="Distributed transactions?" class="md-nav__link">
Distributed transactions?
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#eventual-consistency-and-compensation-1" title="Eventual Consistency and Compensation 1" class="md-nav__link">
Eventual Consistency and Compensation 1
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_3" title="异步确保" class="md-nav__link">
异步确保
<a href="#a-case-for-eventual-consistency" title="A Case for Eventual Consistency" class="md-nav__link">
A Case for Eventual Consistency
</a>
</li>
<li class="md-nav__item">
<a href="#happy-scenario" title="Happy Scenario" class="md-nav__link">
Happy Scenario
</a>
</li>
<li class="md-nav__item">
<a href="#failure-scenarios" title="Failure Scenarios" class="md-nav__link">
Failure Scenarios
</a>
</li>
......@@ -1434,6 +1483,11 @@
</li>
</ul>
</nav>
</li>
......@@ -1453,20 +1507,65 @@
<a href="https://github.com/dotnetcore/CAP/edit/master/docs/user-guide/en/cap/transactions.md" title="Edit this page" class="md-icon md-content__icon">&#xE3C9;</a>
<h1 id="_1">事务<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h1>
<h2 id="_2">分布式事务?<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2>
<p>CAP 不直接提供开箱即用的基于 DTC 或者 2PC 的分布式事务,相反我们提供一种可以用于解决在分布式事务遇到的问题的一种解决方案。</p>
<p>在分布式环境中,由于涉及通讯的开销,使用基于2PC或DTC的分布式事务将非常昂贵,在性能方面也同样如此。另外由于基于2PC或DTC的分布式事务同样受**CAP定理**的约束,当发生网络分区时它将不得不放弃可用性(CAP中的A)。</p>
<p>针对于分布式事务的处理,CAP 采用的是“异步确保”这种方案。</p>
<h3 id="_3">异步确保<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h3>
<p>异步确保这种方案又叫做本地消息表,这是一种经典的方案,方案最初来源于 eBay,参考资料见段末链接。这种方案目前也是企业中使用最多的方案之一。</p>
<p>相对于 TCC 或者 2PC/3PC 来说,这个方案对于分布式事务来说是最简单的,而且它是去中心化的。在TCC 或者 2PC 的方案中,必须具有事务协调器来处理每个不同服务之间的状态,而此种方案不需要事务协调器。
另外 2PC/TCC 这种方案如果服务依赖过多,会带来管理复杂性增加和稳定性风险增大的问题。试想如果我们强依赖 10 个服务,9 个都执行成功了,最后一个执行失败了,那么是不是前面 9 个都要回滚掉?这个成本还是非常高的。</p>
<p>但是,并不是说 2PC 或者 TCC 这种方案不好,因为每一种方案都有其相对优势的使用场景和优缺点,这里就不做过多介绍了。</p>
<h1 id="transaction">Transaction<a class="headerlink" href="#transaction" title="Permanent link">&para;</a></h1>
<h2 id="distributed-transactions">Distributed transactions?<a class="headerlink" href="#distributed-transactions" title="Permanent link">&para;</a></h2>
<p>CAP does not directly provide out-of-the-box MS DTC or 2PC-based distributed transactions, instead we provide a solution that can be used to solve problems encountered in distributed transactions.</p>
<p>In a distributed environment, using 2PC or DTC-based distributed transactions can be very expensive due to the overhead involved in communication, as is performance. In addition, since distributed transactions based on 2PC or DTC are also subject to the <strong>CAP theorem</strong>, it will have to give up availability (A in CAP) when network partitioning occurs.</p>
<blockquote>
<p>中文:<a href="http://www.cnblogs.com/savorboard/p/base-an-acid-alternative.html">http://www.cnblogs.com/savorboard/p/base-an-acid-alternative.html</a><br />
英文:<a href="http://queue.acm.org/detail.cfm?id=1394128">http://queue.acm.org/detail.cfm?id=1394128</a></p>
<p>A distributed transaction is a very complex process with a lot of moving parts that can fail. Also, if these parts run on different machines or even in different data centers, the process of committing a transaction could become very long and unreliable.</p>
<p>This could seriously affect the user experience and overall system bandwidth. So <strong>one of the best ways to solve the problem of distributed transactions is to avoid them completely</strong>.<sup id="fnref2:1"><a class="footnote-ref" href="#fn:1" rel="footnote">1</a></sup></p>
</blockquote>
<p>For the processing of distributed transactions, CAP uses the "Eventual Consistency and Compensation" scheme.</p>
<h3 id="eventual-consistency-and-compensation-1">Eventual Consistency and Compensation <sup id="fnref:1"><a class="footnote-ref" href="#fn:1" rel="footnote">1</a></sup><a class="headerlink" href="#eventual-consistency-and-compensation-1" title="Permanent link">&para;</a></h3>
<p>By far, one of the most feasible models of handling consistency across microservices is <a href="https://en.wikipedia.org/wiki/Eventual_consistency">eventual consistency</a>.</p>
<p>This model doesn’t enforce distributed ACID transactions across microservices. Instead, it proposes to use some mechanisms of ensuring that the system would be eventually consistent at some point in the future.</p>
<h4 id="a-case-for-eventual-consistency">A Case for Eventual Consistency<a class="headerlink" href="#a-case-for-eventual-consistency" title="Permanent link">&para;</a></h4>
<p>For example, suppose we need to solve the following task:</p>
<ul>
<li>register a user profile </li>
<li>do some automated background check that the user can actually access the system</li>
</ul>
<p>The second task is to ensure, for example, that this user wasn’t banned from our servers for some reason.</p>
<p>But it could take time, and we’d like to extract it to a separate microservice. It wouldn’t be reasonable to keep the user waiting for so long just to know that she was registered successfully.</p>
<p><strong>One way to solve it would be with a message-driven approach including compensation</strong>. Let’s consider the following architecture:</p>
<ul>
<li>the user microservice tasked with registering a user profile </li>
<li>the validation microservice tasked with doing a background check </li>
<li>the messaging platform that supports persistent queues </li>
</ul>
<p>The messaging platform could ensure that the messages sent by the microservices are persisted. Then they would be delivered at a later time if the receiver weren’t currently available</p>
<h4 id="happy-scenario">Happy Scenario<a class="headerlink" href="#happy-scenario" title="Permanent link">&para;</a></h4>
<p>In this architecture, a happy scenario would be:</p>
<ul>
<li>the user microservice registers a user, saving information about her in its local database</li>
<li>the user microservice marks this user with a flag. It could signify that this user hasn’t yet been validated and doesn’t have access to full system functionality</li>
<li>a confirmation of registration is sent to the user with a warning that not all functionality of the system is accessible right away</li>
<li>the user microservice sends a message to the validation microservice to do the background check of a user</li>
<li>the validation microservice runs the background check and sends a message to the user microservice with the results of the check</li>
<li>if the results are positive, the user microservice unblocks the user</li>
<li>if the results are negative, the user microservice deletes the user account</li>
</ul>
<p>After we’ve gone through all these steps, the system should be in a consistent state. However, for some period of time, the user entity appeared to be in an incomplete state.</p>
<p>The last step, when the user microservice removes the invalid account, is a compensation phase.</p>
<h4 id="failure-scenarios">Failure Scenarios<a class="headerlink" href="#failure-scenarios" title="Permanent link">&para;</a></h4>
<p>Now let’s consider some failure scenarios:</p>
<ul>
<li>if the validation microservice is not accessible, then the messaging platform with its persistent queue functionality ensures that the validation microservice would receive this message at some later time</li>
<li>suppose the messaging platform fails, then the user microservice tries to send the message again at some later time, for example, by scheduled batch-processing of all users that were not yet validated</li>
<li>if the validation microservice receives the message, validates the user but can’t send the answer back due to the messaging platform failure, the validation microservice also retries sending the message at some later time</li>
<li>if one of the messages got lost, or some other failure happened, the user microservice finds all non-validated users by scheduled batch-processing and sends requests for validation again</li>
</ul>
<p>Even if some of the messages were issued multiple times, this wouldn’t affect the consistency of the data in the microservices’ databases.</p>
<p><strong>By carefully considering all possible failure scenarios, we can ensure that our system would satisfy the conditions of eventual consistency. At the same time, we wouldn’t need to deal with the costly distributed transactions.</strong></p>
<p>But we have to be aware that ensuring eventual consistency is a complex task. It doesn’t have a single solution for all cases.</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>This chapter is quoted from: <a href="https://www.baeldung.com/transactions-across-microservices">https://www.baeldung.com/transactions-across-microservices</a>&#160;<a class="footnote-backref" href="#fnref:1" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a><a class="footnote-backref" href="#fnref2:1" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment