2

ServiceStack.Redis を介して Redis リストを読み取ろうとすると、次のエラーが断続的に発生します: 「トランスポート接続からデータを読み取ることができません: 確立された接続がホスト マシンのソフトウェアによって中止されました」ServiceStack を使用して Redis に確実に接続し、接続をプールする方法の全体的な概念が間違っているかどうか疑問に思っています。これは、sealed クラスとシングルトン パターンを使用して接続するための私のコードです。

public sealed class RedisClientBase
{
    public BasicRedisClientManager Redis;
    private static readonly RedisClientBase instance = new RedisClientBase();

    private RedisClientBase()
    {
        Redis = new BasicRedisClientManager("mypassword@localhost:6379");
    }

    public static RedisClientBase Instance
    {
        get
        {
            return instance;
        }
    }
}

次に、シングルトンを使用する別のクラスをインスタンス化します。

public class RedisBarSetData
{
    private static RedisClient Redis;
    protected IRedisTypedClient<BarSet> redisBarSetClient;
    protected string instrument_key;

    public RedisBarSetData()
    {
        Redis = (RedisClient)RedisClientBase.Instance.Redis.GetClient();
        redisBarSetClient = Redis.As<BarSet>();
    }

    ~RedisBarSetData()
    {
        if (Redis != null)
            Redis.Dispose();
    }

    public List<BarSet> getData(BarSets data)
    {
        setKeys(data);  // instrument_key is set in here
        var redisBarSetClientList = redisBarSetClient.Lists[instrument_key];
        List<BarSet> barSetData;

        barSetData = redisBarSetClientList.GetAll();  // <-- exception here (sometimes)
        return(barSetData);
    }
}

これはインスタンス化され、「サービス」DTO コールバックから呼び出されます。

public class JmaSetsService : Service
{
    public object Get(JmaSets request)
    {
            RedisBarSetData barSetData = new RedisBarSetData();
            BarSets barSets = new BarSets(request);
            barSetList = barSetData.getData(barSets);
            return barSetList;
    }
}

次に、「postman」を使用してこのルートに投稿します。「送信」をクリックすると、ほとんどの場合、データが返されます。例外で終了するものもあります。例外は、コメント「<-- ここで例外」でコードに示されているように、redis から読み取ろうとする場合です。もう1つのポイントは、構成ファイルを設定してパスワードを使用するようにredisを最近構成したことです。以前にこの問題が発生したことを覚えていないので、それについて言及しますが、それも関連していない可能性があります。わかりません。

redis 接続の解放に関して、RedisBarSetData() がスコープ外にある場合、私のデストラクタは Redis.Dispose を呼び出すと考えています。これはそれを処理するための堅実な方法ですか、それともより良い方法がありますか。プールされたクライアントを取得するときに「using」ステートメントを使用する人を見てきましたが、クラス内の 1 か所だけで呼び出しを行うのではなく、多くの「using」ステートメントを使用しています。 .GetClient();" クラスのメソッドがたくさんある場合、すべてのメソッドでコードを繰り返す必要がありますか?

  • 「以前にこの問題があったことを覚えていない」と言うとき、私はこのパターンを数十の動作中の DTO に使用しています。なぜ今失敗しているのかわかりませんか?
4

1 に答える 1

4

非スレッドセーフな Redis TCP 接続をカプセル化する、RedisClientまたはその両方のシングルトン インスタンスを保持しないでください。IRedisTypedClient<BarSet>代わりに - のシングルトン インスタンスを保持できます。IRedisClientsManagerこれは、スレッド セーフな Redis クライアント ファクトリ (DB 接続プールなど) を提供することを目的としています。

ServiceStack サービスも使用している場合は、依存関係を ServiceStack の IOC に登録する方が簡単なのでIRedisClientsManager、他の依存関係と同じように注入できますAppHost.Configure()

container.Register<IRedisClientsManager>(c =>
    new BasicRedisClientManager("mypassword@localhost:6379"));

base.Redisこれにより、ServiceStack サービスで RedisClient プロパティを使用できるようになります。

public class JmaSetsService : Service
{
    public object Get(JmaSets request)
    {
        var redisBarSets = base.Redis.As<BarSet>();
        return redisBarSets.Lists[instument_key].GetAll();
    }
}

使用する場合、 Service によってすでに自動的base.Redisに破棄されているため、RedisClient を明示的に破棄する必要はありません 。

public class Service
{
    ...

    public virtual void Dispose()
    {
        if (redis != null)
            redis.Dispose();
        ...
    }
}

IRedisClientsManagerpublic プロパティまたは Constructor 引数を使用して、他の依存関係と同様に独自のクラスに注入することもできます。

public class RedisBarSetData
{
    public virtual IRedisClientsManager RedisManager { get; set; }

    private IRedisClient redis;
    public virtual IRedisClient Redis
    {
        get { return redis ?? (redis = RedisManager.GetClient()); }
    }

    public override void Dispose()
    {
        if (redis != null)
            redis.Dispose();
    }

    public List<BarSet> getData(BarSets data)
    {
        setKeys(data);  // instrument_key is set in here
        return Redis.As<BarSet>().Lists[instrument_key].GetAll();
    }
}

次に、ServiceStack の IOC に次のように登録して自動配線できます。

container.RegisterAutoWired<RedisBarSetData>();

これにより、サービスの依存関係として使用できます。

public class JmaSetsService : Service
{
    public RedisBarSetData RedisBarSetData { get; set; }

    public object Get(JmaSets request)
    {
        return RedisBarSetData.getData(new BarSets(request));
    }
}

独自の基本クラスを作成する代わりに、既存のLogicBase基本クラスから継承することもできます。これには、既にIRedisClientsManagerプロパティがあり、ボイラープレートの上にあります。

于 2015-01-02T07:29:05.403 に答える