Future

Future は非同期操作の結果を表し、funcs.async() および非同期コントラクト呼び出しから返されます。このページは API リファレンスです。例にあるターゲット ID と引数はアプリケーションが定義します。

ロード

ロード可能なモジュールではありません。Futureは非同期操作によって作成されます:

local funcs = require("funcs")
local future, err = funcs.async("app.compute:task", data)
if err then
    return nil, err
end

レスポンスチャネル

レスポンスチャネルで完了を待ち、その後 Future からキャッシュ済み結果を読み取ります。

local ch = future:response()
local _, open = ch:receive()
if not open then
    return nil, errors.new("future response channel closed")
end

local payload, err = future:result()
if err then
    return nil, err
end
local result, data_err = payload:data()
if data_err then return nil, data_err end

channel()はresponse()のエイリアス。

チャネル値は操作のペイロード、ペイロードテーブル、またはエラーです。チャネルが準備完了になった後に result() を呼ぶと、成功と失敗を一貫した形で処理でき、チャネルを読み終えた後もキャッシュ済み値が返ります。

完了チェック

Futureが完了したかどうかのノンブロッキングチェック:

if future:is_complete() then
    local result, err = future:result()
end

キャンセルチェック

Future がプロバイダーによってキャンセル済みとマークされたかどうかを確認します。

if future:is_canceled() then
    print("Operation was canceled")
end

結果の取得

キャッシュされた結果を取得(ノンブロッキング):

local val, err = future:result()

戻り値:

  • 未完了:nil, nil
  • キャンセル済み:nil, error(kind CANCELED)
  • エラー:nil, error
  • 成功:Payload, nilまたはtable, nil(複数ペイロード)

エラーの取得

Futureが失敗した場合のエラーを取得:

local err, has_error = future:error()
if has_error then
    print("Failed:", err:message())
end

戻り値: error, boolean

操作が失敗した場合、error() は再試行不可の INTERNAL ラッパーを返します。呼び出した関数の元のエラー種別と再試行可能性を保持する必要がある場合は result() を使用してください。

キャンセル

非同期操作をキャンセル(ベストエフォート):

local canceled, err = future:cancel()

戻り値: boolean, error

操作が既に進行中の場合でも完了する可能性あり。

戻り値: boolean, error

ランタイムv0.3.32aでは、関数Futureとcontract Futureがプロセス全体で1つのキャンセルコールバックを共有します。両方のproviderが読み込まれている場合、cancel()とis_canceled()はproviderをまたぐ安定した契約ではありません。アプリケーションの正しさをキャンセルに依存させず、ローカルでタイムアウトし、ランタイムがproviderごとのキャンセルを分離するまでは遅れて届いた結果を無視してください。

タイムアウトパターン

local time = require("time")

local future, err = funcs.async("app.compute:slow", data)
if err then
    return nil, err
end

local timeout, err = time.after("5s")
if err then
    return nil, err
end

local r = channel.select {
    future:channel():case_receive(),
    timeout:case_receive()
}

if r.channel == timeout then
    future:cancel()
    return nil, errors.new({ kind = errors.TIMEOUT, message = "Operation timed out" })
end

local payload, result_err = future:result()
if result_err then
    return nil, result_err
end
local value, data_err = payload:data()
if data_err then return nil, data_err end
return value

最初に完了したもの

local f1, err = funcs.async("app.cache:get", key)
if err then
    return nil, err
end
local f2, err = funcs.async("app.db:get", key)
if err then
    return nil, err
end

local ch1 = f1:channel()
local ch2 = f2:channel()

local r = channel.select {
    ch1:case_receive(),
    ch2:case_receive()
}

-- The slower operation may still complete; this caller ignores its result.
local winner
if r.channel == ch1 then
    winner = f1
else
    winner = f2
end

local payload, result_err = winner:result()
if result_err then
    return nil, result_err
end
local value, data_err = payload:data()
if data_err then return nil, data_err end
return value

エラー

条件 種別
操作がキャンセルされた CANCELED
非同期操作が失敗 result()は操作の kind を保持する。error()はINTERNALを報告する