public static void Publish <T>(T data, ProcessType processType = ProcessType.Topic)
        {
            var type = data.GetType().AssemblyQualifiedName;

            RedisServices.HashSet(_keyListChannelName, new KeyValuePair <string, string>(type, processType.ToString()));

            string queueDataName = GetKeyQueueDataForChannel(type);

            RedisServices.TryEnqueue(queueDataName, JsonConvert.SerializeObject(data));
        }
        public static void Subscribe(string subscriberName, string typeFullAssemblyQualifiedName, Action <object> handle)
        {
            var type = typeFullAssemblyQualifiedName;

            string channelSubscriber = GetKeySubscribersForChannel(type);

            if (RedisServices.HashExisted(channelSubscriber, subscriberName))
            {
                //todo: should unsubscribe before subscribe
                //throw new MessageBussServices.ExistedSubscriber($"Existed subscriber {subscriberName} in channel {channelSubscriber}");
            }

            RedisServices.HashSet(channelSubscriber, new KeyValuePair <string, string>(subscriberName, subscriberName));

            string channelPubSubChild = GetKeyToRealPublishFromChannelToSubscriber(subscriberName, type, ProcessType.Topic.ToString());

            //regist to process data for data structure pubsub
            RedisServices.Subscribe(channelPubSubChild, (data) =>
            {
                TryDoJob(typeFullAssemblyQualifiedName, data, handle);
            });

            string channelPubSubParent = GetKeyToRealPublishFromChannelToSubscriber(string.Empty, type, ProcessType.Topic.ToString());

            //regist to process if pubsub try dequeue get data and publish to subscriber
            RedisServices.Subscribe(channelPubSubParent, (msg) =>
            {
                string data;
                string queueDataName = GetKeyQueueDataForChannel(type);
                while (RedisServices.TryDequeue(queueDataName, out data))
                {
                    var subscribers = RedisServices.HashGetAll(channelSubscriber);

                    foreach (var subc in subscribers)
                    {
                        string queueDataNameChannelSubscriber = GetKeyToRealPublishFromChannelToSubscriber(subc.Key, type, ProcessType.Topic.ToString());
                        //channelPubSubChild
                        RedisServices.Publish(queueDataNameChannelSubscriber, data);
                    }
                }
            });

            string channelQueue = GetKeyToRealPublishFromChannelToSubscriber(subscriberName, type, ProcessType.Queue.ToString());

            //regist to process if data structure is queue
            RedisServices.Subscribe(channelQueue, (msg) =>
            {
                string data;
                string queueDataName = GetKeyQueueDataForChannel(type);
                while (RedisServices.TryDequeue(queueDataName, out data))
                {
                    TryDoJob(type, data, handle);
                }
            });

            string channelStack = GetKeyToRealPublishFromChannelToSubscriber(subscriberName, type, ProcessType.Stack.ToString());

            //regist to process if data structure is stack
            RedisServices.Subscribe(channelStack, (msg) =>
            {
                string data;
                string queueDataName = GetKeyQueueDataForChannel(type);
                while (RedisServices.TryPop(queueDataName, out data))
                {
                    TryDoJob(type, data, handle);
                }
            });
        }