2

我有 2 个服务在同一个 thrift 文件中定义并共享一个端口。我可以使用 serviceA 中的任何方法没问题,但是每当我尝试调用 ServiceB 的任何方法时,我都会遇到异常。这是我的节俭文件(service-a.thrift):

service ServiceA extends common.CommonService {
    list<i64> getByIds(1: list<i64> ids)
    ...
}

service ServiceB extends common.CommonService {
    list<i64> getByIds(1: list<i64> ids)
    ...
}

笔记:

  • 我正在使用 python 客户端
  • 节俭版 0.8.0

有任何想法吗?

4

2 回答 2

1

我们也有这个需求,并通过编写一个新的 TProcessor 实现来解决这个需求,该实现创建了多个处理器的映射。唯一的问题是,使用此实现,您需要确保没有方法名称重叠 - 即不要在不同的服务器中使用像 Run() 这样好的通用名称。抱歉没有将 C# 转换为 Python...

示例类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Thrift;
using Thrift.Protocol;

/// <summary>
/// Processor that allows for multiple services to run under one roof.  Requires no method name conflicts across services.
/// </summary>
public class MultiplexProcessor : TProcessor {

    public MultiplexProcessor(IEnumerable<TProcessor> processors) {
        ProcessorMap = new Dictionary<string, Tuple<TProcessor, Delegate>>();
        foreach (var processor in processors) {
            var processMap = (IDictionary) processor.GetType().GetField("processMap_", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(processor);
            foreach (string pmk in processMap.Keys) {
                var imp = (Delegate) processMap[pmk];
                try {
                    ProcessorMap.Add(pmk, new Tuple<TProcessor, Delegate>(processor, imp));
                }
                catch (ArgumentException) {
                    throw new ArgumentException(string.Format("Method already exists in process map: {0}", pmk));
                }
            }
        }
    }

    protected readonly Dictionary<string, Tuple<TProcessor, Delegate>> ProcessorMap;

    internal protected Dictionary<string, Tuple<TProcessor, Delegate>> GetProcessorMap() {
        return new Dictionary<string, Tuple<TProcessor, Delegate>>(ProcessorMap);
    }

    public bool Process(TProtocol iprot, TProtocol oprot) {
        try {
            TMessage msg = iprot.ReadMessageBegin();
            Tuple<TProcessor, Delegate> fn;
            ProcessorMap.TryGetValue(msg.Name, out fn);
            if (fn == null) {
                TProtocolUtil.Skip(iprot, TType.Struct);
                iprot.ReadMessageEnd();
                var x = new TApplicationException(TApplicationException.ExceptionType.UnknownMethod, "Invalid method name: '" + msg.Name + "'");
                oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));
                x.Write(oprot);
                oprot.WriteMessageEnd();
                oprot.Transport.Flush();
                return true;
            }

            Console.WriteLine("Invoking service method {0}.{1}", fn.Item1, fn.Item2);
            fn.Item2.Method.Invoke(fn.Item1, new object[] {msg.SeqID, iprot, oprot});
        }
        catch (IOException) {
            return false;
        }
        return true;
    }
}

示例用法:

        Processor = new MultiplexProcessor(
            new List<TProcessor> {
                                     new ReportingService.Processor(new ReportingServer()),
                                     new MetadataService.Processor(new MetadataServer()),
                                     new OtherService.Processor(new OtherService())
                                 }
            );
        Server = new TThreadPoolServer(Processor, Transport);
于 2013-06-07T13:49:27.967 回答
0

As far as I know, there's no straightforward way to bind several services to a single port without adding this field to TMessage and recompiling thrift. If you want to have two services using the same Server, you should reimplement Thrift Server, which it doesn't seem an easy task

于 2013-05-02T08:07:37.417 回答