WebAPi的可視化輸出模式(RabbitMQ、消息補償相關)——全部webapi彷佛都缺失的一個功能

最近的工做我在作一個有關於消息發送和接受封裝工做。大概流程是這樣的,消息中間件是採用rabbitmq,爲了保證消息的絕對無丟失,咱們須要在發送和接受前對消息進行DB落地。在發送前我會先進行DB的插入,單表插入,因此在性能上也是能接受的,單表插入作了壓測基本上是一到兩毫秒的時間,加上消息的發送(有ACK)再加上集羣是兩個節點的高可用(一個磁盤持久化節點),單臺TPS基本上是在2000-3000左右。這對於咱們的業務場景來講是夠用了。一旦當消息丟失或者因爲網絡問題、集羣問題業務不會中斷,消息就算髮不出去也不要緊,咱們會進行消息的補償或者同步api調用補償。這是架構設計的必需要考慮的A計劃、B計劃、C計劃,這是敬畏或者危機意識。linux

你可能又要說兩個節點或者三個節點的集羣怎麼會有問題,那你就錯了,大錯特錯。只能說明你並不瞭解什麼叫分佈式系統及分佈式系統的特性。你也許不會知道網絡抖動、網絡閃斷致使socket斷開如何進行心跳重試已保持有效的Rabbitmq Connection。當你的網絡極不穩定,你的linux keepalived VIP 來回漂移,致使你的ARP根本沒法成效,可能就連廣播都傳不出去,而客戶端則在一直使用一個無用的IP地址。當你的集羣節點之間沒法鏈接成一個總體的時候各類奇葩的問題又來了。這些都是可能致使你的集羣出問題的緣由,因此不要大意。web

(後面我會整理一篇專門講解「rabbitmq高可用、故障轉移集羣架構「文章,因此這裏咱們就不繼續介紹了)json

這是一個鋪墊,本文的重點是介紹下我在嘗試使用可視化webapi的輸出模式,這比本來json的輸出模式看起來會方便許多。若是你的api提供兩種輸出模式,人性化絕對很好。如今不少後端api都是沒有界面的都是隻提供了一個json輸出。然而,咱們其實很須要一個可讀性很強的輸出模式。後端

我在開發消息補償程序的時候,我借鑑了這一思想進行了嘗試。先來看下總體架構藍圖:api

1

本篇文章要介紹的是有關於這個補償程序的api的可視化輸出內容。不涉及到消息相關太多的東西,只是爲了讓這個可視化輸出看起來容易理解點。這個補償程序須要對發送的消息和接受的消息進行查詢和比較而後輸出,用來肯定消息的發送是失敗了仍是成功的。簡單邏輯就是比較某個時間段內的消息發送表和接受表,而後進行消息id的匹配。網絡

我在想這個數據反饋到api上是個什麼樣子的,按照常規設計就是兩個字段:架構

/// <summary> 
/// 接受的消息對象。 
/// </summary> 
public class ReceiveMessage 
{ 
    /// <summary> 
    /// 發送消息ID。 
    /// </summary> 
    public string SendMessageId { get; set; }

    /// <summary> 
    /// 接受消息ID。 
    /// </summary> 
    public string ReceiveMessageId { get; set; } 
}

這表示一個消息從發送到接受的一個過程。若是失敗了,多是隻有SendMessageId而沒有ReceiveMessageId。而後我纔會針對沒有ReceiveMessageId的消息進行自動補償。在開發的時候只有幾十條消息,輸出到postman中的看起來也還行,可是不直觀。app

2

GetReceiveMessage是獲取接受消息列表,就是查看當前消息發送到接受是個什麼狀態。socket

/// <summary> 
/// 處理成功消息對象。 
/// </summary> 
public class SuccessMessage 
{ 
    /// <summary> 
    /// 發送消息ID 
    /// </summary> 
    public string SendMessageId { get; set; }

    /// <summary> 
    /// 接受消息ID 
    /// </summary> 
    public string ReceiveMessageId { get; set; }

    /// <summary> 
    /// 處理成功消息ID 
    /// </summary> 
    public string SuccessMessageId { get; set; } 
}

SuccessMessage表示處理成功消息狀況。此時有多是有SendMessageId,ReceiveMessageId消息,可是SuccessMessageId多是沒有的。就會針對處理成功的消息進行發送。分佈式

3

忽然受到ElasticSearch的_cat endpoint 啓發。彷佛這裏我能夠嘗試下,webapi帶有兩種輸出模式,一種是針對程序使用的json輸出模式,另一種是針對人能夠閱讀的模式text/plain模式,而第二種模式能夠簡單的理解爲是行列轉換缺省模式。

4

是否是看起來會很舒服。這在進行消息的時間段查看很是有幫助,若是還按照本來的json輸出模式可能看起來會比較吃力。

來看下基本的api的設計,爲了保證你的全部api支持?v可視化模式,須要必定的抽象:

5

須要定義一種ViewModel,全部的數據都輸出這種對象,固然我這裏也只是簡單地封裝。若是能夠,其實能夠專門提取出一個庫出來,包括對文本的輸出自動化。

咱們看下BaseApiController:

 public class BaseApiController : ApiController
    {
        public class ViewModel
        {
            public string Content { get; set; }
            public object JsonObject { get; set; }
            public bool Success = true;
        }

        protected bool IsView;
        private const string ViewQuerystring = "?v";
        public ViewModel ResultModel;
        private const string CheckToken = "CheckToken";
        private const string Token = "49BBD022-CDBF-4F94-80E4-5BCACB1192EC";
        private bool _checkStatus;

        public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
        {
            //驗證token
            if (controllerContext.Request.Headers != null && controllerContext.Request.Headers.Contains(CheckToken))
            {
                var requestToken = controllerContext.Request.Headers.GetValues(CheckToken).FirstOrDefault();
                if (requestToken != null && requestToken.Equals(Token))
                {
                    this._checkStatus = true;
                }
            }

            if (!_checkStatus)
            {
                var checkResult = new Task<HttpResponseMessage>(() => new HttpResponseMessage
                {
                    Content = new StringContent("非法訪問,缺乏token", Encoding.UTF8, "text/plain")
                }, cancellationToken);

                checkResult.Start();
                return checkResult;
            }

            if (controllerContext.Request.RequestUri.Query.Equals(ViewQuerystring))
                this.IsView = true;

            base.ExecuteAsync(controllerContext, cancellationToken);

            //text模式
            if (this.IsView)
            {
                var textResult = new Task<HttpResponseMessage>(() => new HttpResponseMessage
                {
                    Content = new StringContent(this.ResultModel.Content, Encoding.UTF8, "text/plain")
                }, cancellationToken);

                textResult.Start();
                return textResult;
            }

            //json模式
            var resultData = new Result<object>
            {
                Data = this.ResultModel.JsonObject,
                Type = this.ResultModel.Success ? ResultType.Successfully : ResultType.Failure
            };

            var jsonResult = new Task<HttpResponseMessage>(() => new HttpResponseMessage
            {
                Content = new ObjectContent(typeof(Result), resultData, new JsonMediaTypeFormatter(), "application/json")
            }, cancellationToken);

            jsonResult.Start();

            return jsonResult;
        }
    }

  

代碼很簡單,這裏給咱們一個啓發,webapi是否是真的缺乏了一個可視化模式。

相關文章
相關標籤/搜索