Conversation
| } | ||
| } | ||
|
|
||
| public void Dispose() |
There was a problem hiding this comment.
constructor で httpClient を作ってるので、せっかくなので IDisposable にします
| /// </summary> | ||
|
|
||
| public class ApiClientCore | ||
| public class ApiClientCore : IDisposable |
| return response; | ||
| else | ||
| { | ||
| return apiClientCore.Get(request, isConfigureAwait).Result; |
There was a problem hiding this comment.
この時点で取得を待って動くようにします。当然ながら cache からは常に string が直接返ってくるので、こっちのが全体として違和感がないと思う。
| } | ||
|
|
||
| public async Task<JObject> GetQuarter(string ticker, FiscalQuarterPeriod period, bool useOndemand, bool isConfigureAwait = true, bool useCache = true) | ||
| public JObject GetQuarter(string ticker, FiscalQuarterPeriod period, bool useOndemand, bool isConfigureAwait = true, bool useCache = true) |
There was a problem hiding this comment.
ApiClientCoreWithCache が同期的に動くようになったので、ここも Json をそのまま返します
| } | ||
|
|
||
| private void textAPIKey_TextChanged(object sender, EventArgs e) | ||
| private void TextAPIKey_TextChanged(object sender, EventArgs e) |
There was a problem hiding this comment.
命名規則で怒られてたので、大文字始まりにしておきました
| textAPIKey.Text = setting.ApiKey; | ||
| checkDebugMode.Checked = setting.DebugMode; | ||
| checkIsOndemandEndpointEnabled.Checked = setting.IsOndemandEndpointEnabled; | ||
| var maxDegreeOfParallelism = setting.MaxDegreeOfParallelism; |
There was a problem hiding this comment.
並行実行を渡す開発者オプションを削除します
| public static PeriodSupportedTierResolver Create(IBuffettCodeApiClient apiClient, IApiResponseParser parser) => new PeriodSupportedTierResolver(apiClient, parser, new SupportedTierDictionary()); | ||
|
|
||
| public SupportedTier Resolve(DataTypeConfig dataType, string ticker, IPeriod period) | ||
| public SupportedTier Resolve(DataTypeConfig dataType, string ticker, IPeriod period, bool isConfigureAwait, bool useCache) |
There was a problem hiding this comment.
isConfigureAwait と useCache を外から渡せるように変更しています
| Assert.AreEqual(SupportedTier.OndemandTier, helper.FindAvailableTier(DataTypeConfig.Quarter, ticker, ondemandOldest.Next() as FiscalQuarterPeriod, true)); | ||
| Assert.AreEqual(SupportedTier.OndemandTier, helper.FindAvailableTier(DataTypeConfig.Quarter, ticker, ondemandLatest, true)); | ||
| Assert.ThrowsException<NotSupportedTierException>(() => helper.FindAvailableTier(DataTypeConfig.Quarter, ticker, ondemandLatest.Next() as FiscalQuarterPeriod, true)); | ||
| Assert.AreEqual(SupportedTier.FixedTier, helper.FindAvailableTier(DataTypeConfig.Quarter, ticker, fixedOldest, true, true, true)); |
There was a problem hiding this comment.
test は 両方とも true の、 UDF と同じ仕様で動かします
There was a problem hiding this comment.
CSVダウンロードように、 ConfigureAwait(false) のケースもテストしたほうがいいと思う
| var quarters = PeriodRange<FiscalQuarterPeriod>.Slice(parameters.Range, 12) | ||
| .SelectMany | ||
| (r => processor.GetApiResources(DataTypeConfig.Quarter, parameters.Ticker, r.From, r.To, true, true) | ||
| (r => processor.GetApiResources(DataTypeConfig.Quarter, parameters.Ticker, r.From, r.To, false, true) |
There was a problem hiding this comment.
ここを true で渡すと、リボンから呼ぶとすごく遅くなるので false にします
https://devblogs.microsoft.com/dotnet/configureawait-faq/#why-would-i-want-to-use-configureawaitfalse
There was a problem hiding this comment.
ConfigureAwait(true) にしたいケースがほとんど存在しないし (テストが書きやすいくらい?)、基本的に ConfigureAwait(false) でハードコードしたほうが安全な気がしてる
| /// <summary> | ||
| /// 最大同時実行数のデフォルト値 | ||
| /// </summary> | ||
| private static readonly uint MaxDegreeOfParallelismDefault = 8; |
akiomik
left a comment
There was a problem hiding this comment.
単体テストで実APIを呼び出すのは単体テストの責務から外れてるように感じるので、モックを使うように書き直して欲しいです 🙏
| /// </summary> | ||
|
|
||
| public class ApiClientCore : IDisposable | ||
| public class ApiClientCore : IDisposable, IApiClientCore |
There was a problem hiding this comment.
実際にhttp通信を行うこいつを差し替えられるようにします
| return new ApiClientCoreWithCache(apiClientCore, cacheHelper); | ||
| } | ||
|
|
||
| public static ApiClientCoreWithCache Create(string apiKey, Uri baseUrl, MemoryCache cache) |
There was a problem hiding this comment.
この Create は誰も使ってなかったので削除
| } | ||
|
|
||
| public static ApiClientCoreWithCache Create(string apiKey, Uri baseUrl, MemoryCache cache) | ||
| public static ApiClientCoreWithCache Create(IApiClientCore apiClientCore, ApiRequestCacheHelper cacheHelper) |
| var mockApiClientCore = new ErrorMockApiClientCore("dummy"); | ||
| var client = ApiClientCoreWithCache.Create(mockApiClientCore, CreateCheHelperForTest()); | ||
| ApiGetRequest request = new ApiGetRequest("dummy endpoint", new Dictionary<string, string>()); | ||
| Assert.ThrowsException<BuffettCodeApiClientException>(() => client.Get(request, false, false)); |
There was a problem hiding this comment.
clientCore が例外を投げた場合はそのまま投げることを確認しています
| Assert.AreEqual(request.ToString(), client.Get(request, false, true)); | ||
|
|
||
| // don't use cache | ||
| Assert.AreEqual(request.ToString(), client.Get(request, false, false)); |
There was a problem hiding this comment.
cahceを使っても使わなくても、同じ結果が返ることを確認しています
| var mockApiClientCore = new MockApiclientCore("dummy"); | ||
| var client = ApiClientCoreWithCache.Create(mockApiClientCore, CreateCheHelperForTest()); | ||
| ApiGetRequest request = new ApiGetRequest("dummy endpoint", new Dictionary<string, string>()); | ||
| Assert.AreEqual(request.ToString(), client.Get(request, false, true)); |
| [TestClass()] | ||
| public class ApiClientCoreWithCacheTests | ||
| { | ||
| private static ApiRequestCacheHelper CreateCheHelperForTest() |
There was a problem hiding this comment.
test ごとにcache helper を作ります。
| return await response.Content.ReadAsStringAsync().ConfigureAwait(isConfigureAwait); | ||
| var content = response.Content.ReadAsStringAsync().Result; |
There was a problem hiding this comment.
ReadAsStringAsync().Result って危険な呼び出しにみえるけど、非同期処理が未完了だったらブロックしてくれると。
https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.task-1.result?view=net-5.0#--
| { | ||
| public interface IApiClientCore | ||
| { | ||
| Task<string> Get(ApiGetRequest request, bool isConfigureAwait); |
There was a problem hiding this comment.
using (var response = await httpClient.GetAsync(path).ConfigureAwait(isConfigureAwait)) しているのでシグニチャは Task<string> のまま、と
There was a problem hiding this comment.
これどうするかすごい迷ったけど、この ApiClientCore の通信部分は非同期に呼び出す前提にしておいたほうがいいと思う。
string 直接返す client が Task<string> に変換して返すのは全然難しくないし
There was a problem hiding this comment.
将来的には非同期クライアントになってるほうがいいと思うので、内部的には半同期みたいな感じでもシグニチャはこのままでいいと思う
| Assert.ThrowsExceptionAsync<InvalidAPIKeyException> | ||
| (() => client.GetDaily("6502", day, true, true, false)); |
There was a problem hiding this comment.
そそ、 http 通信のlogic が処理の真ん中に入っちゃってるんだよね。そとから clientCore を渡す形の VxApiClientHelper みたいなやつを作って、各 client はその static な関数を呼ぶだけにしようと思う
| private void CheckDebugMode_CheckedChanged(object sender, EventArgs e) | ||
| { | ||
|
|
||
| } |
There was a problem hiding this comment.
そう、formのUIをいじると勝手に作られる event handler 用の関数
to close: #34
非同期処理の制御がうまくいっていなかったために deadlock が起こってしまっていたっぽい
ApiClientCoreのみで行うようにする & await の設定をキチンと引き継ぐ