私は基本的にPostgreSQL
、特定のテーブルの増加に対する挿入パフォーマンスをベンチマークするプログラムを少し作成しています。Martenを使用してデータを挿入するときに、データベースが挿入を完全に受け入れる準備ができていることを確認したいと思います。
Docker.DotNetを使用して、最新のPostgreSQL
イメージを実行する新しいコンテナーを生成していますが、コンテナーがrunning
状態にある場合でも、そのコンテナー内で実行されているPostgreが当てはまらない場合があります。
もちろん、追加することもできますThread. Sleep
が、これは少しランダムなので、データベースが挿入を受け入れる準備ができたときに、決定論的な何かを把握したいですか?
public static class Program
{
public static async Task Main(params string[] args)
{
const string imageName = "postgres:latest";
const string containerName = "MyProgreSQL";
var client = new DockerClientConfiguration(Docker.DefaultLocalApiUri).CreateClient();
var containers = await client.Containers.SearchByNameAsync(containerName);
var container = containers.SingleOrDefault();
if (container != null)
{
await client.Containers.StopAndRemoveContainerAsync(container);
}
var createdContainer = await client.Containers.RunContainerAsync(new CreateContainerParameters
{
Image = imageName,
HostConfig = new HostConfig
{
PortBindings = new Dictionary<string, IList<PortBinding>>
{
{"5432/tcp", new List<PortBinding>
{
new PortBinding
{
HostPort = "5432"
}
}}
},
PublishAllPorts = true
},
Env = new List<string>
{
"POSTGRES_PASSWORD=root",
"POSTGRES_USER=root"
},
Name = containerName
});
var containerState = string.Empty;
while (containerState != "running")
{
containers = await client.Containers.SearchByNameAsync(containerName);
container = containers.Single();
containerState = container.State;
}
var store = DocumentStore.For("host=localhost;database=postgres;password=root;username=root");
var stopwatch = new Stopwatch();
using (var session = store.LightweightSession())
{
var orders = OrderHelpers.FakeOrders(10000);
session.StoreObjects(orders);
stopwatch.Start();
await session.SaveChangesAsync();
var elapsed = stopwatch.Elapsed;
// Whatever else needs to be done...
}
}
}
参考までに、実行している行の前で一時停止せずに上記のプログラムをawait session.SaveChangesAsync();
実行している場合は、次の例外が発生します。
Unhandled Exception: Npgsql.NpgsqlException: Exception while reading from stream ---> System.IO.EndOfStreamException: Attempted to read past the end of the streams.
at Npgsql.NpgsqlReadBuffer.<>c__DisplayClass31_0.<<Ensure>g__EnsureLong|0>d.MoveNext() in C:\projects\npgsql\src\Npgsql\NpgsqlReadBuffer.cs:line 154
--- End of inner exception stack trace ---
at Npgsql.NpgsqlReadBuffer.<>c__DisplayClass31_0.<<Ensure>g__EnsureLong|0>d.MoveNext() in C:\projects\npgsql\src\Npgsql\NpgsqlReadBuffer.cs:line 175
--- End of stack trace from previous location where exception was thrown ---
at Npgsql.NpgsqlConnector.<>c__DisplayClass161_0.<<ReadMessage>g__ReadMessageLong|0>d.MoveNext() in C:\projects\npgsql\src\Npgsql\NpgsqlConnector.cs:l
ine 955
--- End of stack trace from previous location where exception was thrown ---
at Npgsql.NpgsqlConnector.Authenticate(String username, NpgsqlTimeout timeout, Boolean async) in C:\projects\npgsql\src\Npgsql\NpgsqlConnector.Auth.cs
:line 26
at Npgsql.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken) in C:\projects\npgsql\src\Npgsql\NpgsqlConne
ctor.cs:line 425
at Npgsql.ConnectorPool.AllocateLong(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken) in C:\projects\
npgsql\src\Npgsql\ConnectorPool.cs:line 246
at Npgsql.NpgsqlConnection.<>c__DisplayClass32_0.<<Open>g__OpenLong|0>d.MoveNext() in C:\projects\npgsql\src\Npgsql\NpgsqlConnection.cs:line 300
--- End of stack trace from previous location where exception was thrown ---
at Npgsql.NpgsqlConnection.Open() in C:\projects\npgsql\src\Npgsql\NpgsqlConnection.cs:line 153
at Marten.Storage.Tenant.generateOrUpdateFeature(Type featureType, IFeatureSchema feature)
at Marten.Storage.Tenant.ensureStorageExists(IList`1 types, Type featureType)
at Marten.Storage.Tenant.ensureStorageExists(IList`1 types, Type featureType)
at Marten.Storage.Tenant.StorageFor(Type documentType)
at Marten.DocumentSession.Store[T](T[] entities)
at Baseline.GenericEnumerableExtensions.Each[T](IEnumerable`1 values, Action`1 eachAction)
at Marten.DocumentSession.StoreObjects(IEnumerable`1 documents)
at Benchmark.Program.Main(String[] args) in C:\Users\eperret\Desktop\Benchmark\Benchmark\Program.cs:line 117
at Benchmark.Program.<Main>(String[] args)
[編集]
私は答えを受け入れましたが、健康パラメータの同等性に関するバグのため、答えでDocker.DotNet
与えられた解決策を活用できませんでした(実際に可能であれば、.NETクライアントでそのdockerコマンドを適切に変換すると思います)最良の解決策。その間、これが私の問題を解決する方法です。基本的に、結果が正常になるまで、ヘルスチェックで実行されると予想されていたコマンドをポーリングします。
Program.cs
、コードの実際の内容:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Benchmark.DockerClient;
using Benchmark.Domain;
using Benchmark.Utils;
using Docker.DotNet;
using Docker.DotNet.Models;
using Marten;
using Microsoft.Extensions.Configuration;
namespace Benchmark
{
public static class Program
{
public static async Task Main(params string[] args)
{
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = new Configuration();
configurationBuilder.Build().Bind(configuration);
var client = new DockerClientConfiguration(DockerClient.Docker.DefaultLocalApiUri).CreateClient();
var containers = await client.Containers.SearchByNameAsync(configuration.ContainerName);
var container = containers.SingleOrDefault();
if (container != null)
{
await client.Containers.StopAndRemoveContainerAsync(container.ID);
}
var createdContainer = await client.Containers.RunContainerAsync(new CreateContainerParameters
{
Image = configuration.ImageName,
HostConfig = new HostConfig
{
PortBindings = new Dictionary<string, IList<PortBinding>>
{
{[email protected]"{configuration.ContainerPort}/{configuration.ContainerPortProtocol}", new List<PortBinding> { new PortBinding { HostPort = configuration.HostPort } }} }, PublishAllPorts = true }, Env = new List<string> { $"POSTGRES_USER={configuration.Username}",
$"POSTGRES_PASSWORD={configuration.Password}" }, Name = configuration.ContainerName }); var isContainerReady = false; while (!isContainerReady) { var result = await client.Containers.RunCommandInContainerAsync(createdContainer.ID, "pg_isready -U postgres"); if (result.stdout.TrimEnd('\n') == $"/var/run/postgresql:{configuration.ContainerPort} - accepting connections")
{
isContainerReady = true;
}
}
var store = DocumentStore.For($"host=localhost;" + $"database={configuration.DatabaseName};" +
$"username={configuration.Username};" + $"password={configuration.Password}");
// Whatever else needs to be done...
}
}
で定義されている拡張機能ContainerOperationsExtensions.cs
:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Docker.DotNet;
using Docker.DotNet.Models;
namespace Benchmark.DockerClient
{
public static class ContainerOperationsExtensions
{
public static async Task<IList<ContainerListResponse>> SearchByNameAsync(this IContainerOperations source, string name, bool all = true)
{
return await source.ListContainersAsync(new ContainersListParameters
{
All = all,
Filters = new Dictionary<string, IDictionary<string, bool>>
{
{"name", new Dictionary<string, bool>
{
{name, true}
}
}
}
});
}
public static async Task StopAndRemoveContainerAsync(this IContainerOperations source, string containerId)
{
await source.StopContainerAsync(containerId, new ContainerStopParameters());
await source.RemoveContainerAsync(containerId, new ContainerRemoveParameters());
}
public static async Task<CreateContainerResponse> RunContainerAsync(this IContainerOperations source, CreateContainerParameters parameters)
{
var createdContainer = await source.CreateContainerAsync(parameters);
await source.StartContainerAsync(createdContainer.ID, new ContainerStartParameters());
return createdContainer;
}
public static async Task<(string stdout, string stderr)> RunCommandInContainerAsync(this IContainerOperations source, string containerId, string command)
{
var commandTokens = command.Split(" ", StringSplitOptions.RemoveEmptyEntries);
var createdExec = await source.ExecCreateContainerAsync(containerId, new ContainerExecCreateParameters
{
AttachStderr = true,
AttachStdout = true,
Cmd = commandTokens
});
var multiplexedStream = await source.StartAndAttachContainerExecAsync(createdExec.ID, false);
return await multiplexedStream.ReadOutputToEndAsync(CancellationToken.None);
}
}
}
Docker.cs
ローカルのdockerapi uriを取得するには:
using System;
using System.Runtime.InteropServices;
namespace Benchmark.DockerClient
{
public static class Docker
{
static Docker()
{
DefaultLocalApiUri = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? new Uri("npipe://./pipe/docker_engine")
: new Uri("unix:/var/run/docker.sock");
}
public static Uri DefaultLocalApiUri { get; }
}
}
カスタムhealtcheckを使用して、データベースが接続を受け入れる準備ができているかどうかを確認することをお勧めします。
Dockerの.NETクライアントに精通していませんが、次のdocker run
コマンドは何を試すべきかを示しています。
docker run --name postgres \
--health-cmd='pg_isready -U postgres' \
--health-interval='10s' \
--health-timeout='5s' \
--health-start-period='10s' \
postgres:latest
時間パラメータは、ニーズに応じて更新する必要があります。
このhealtcheckが設定されていると、コンテナは「状態になるため、アプリケーションが待機する必要があり健全な」データベースに接続しようとする前に。その特定の場合のステータス「healthy」は、コマンドpg_isready -U postgres
が成功したことを意味します(したがって、データベースは接続を受け入れる準備ができています)。
コンテナのステータスは次の方法で取得できます。
docker inspect --format "{{json .State.Health.Status }}" postgres
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
写真:Lefteris Pitarakis / AP NBAドラフトクラスがどれだけ優れているかを予測するのはお粗末な練習ですが、誰もが知る限り、2018NBAドラフトのトップがロードされているようです。新入生のマービンバグリー3世、マイケルポータージュニア
Tomorrow's Kitchen シリコンストレッチ蓋 12個パック | $14 | アマゾン | プロモーション コード 20OFFKINJALids は基本的にキッチンの靴下です。常に迷子になり、二度と閉じられない孤立したコンテナーが残ります。しかし、蓋が伸びて、残った容器、鍋、フライパン、さらには大きなスライスされた果物のすべてに適合するとしたらどうでしょうか? その非常に特殊な蓋を失うことを二度と心配する必要はありません。
ある小売業者は、プラスサイズのセクションを缶詰にしています。しかし、彼らはこのカテゴリーをオンラインのみにとどめたり、完全に廃止したりしているわけではありません。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。