build/extracted-examples/guides/hack/15-asynchronous-operations/28-guidelines/batching.hack (46 lines of code) (raw):
// WARNING: Contains some auto-generated boilerplate code, see:
// HHVM\UserDocumentation\MarkdownExt\ExtractedCodeBlocks\FilterBase::addBoilerplate
namespace HHVM\UserDocumentation\Guides\Hack\AsynchronousOperations\Guidelines\Batching;
use namespace HH\Lib\Vec;
async function b_one(string $key): Awaitable<string> {
$subkey = await Batcher::lookup($key);
return await Batcher::lookup($subkey);
}
async function b_two(string $key): Awaitable<string> {
return await Batcher::lookup($key);
}
async function batching(): Awaitable<void> {
$results = await Vec\from_async(vec[b_one('hello'), b_two('world')]);
\printf("%s\n%s\n", $results[0], $results[1]);
}
<<__EntryPoint>>
function main(): void {
\init_docs_autoloader();
\HH\Asio\join(batching());
}
class Batcher {
private static vec<string> $pendingKeys = vec[];
private static ?Awaitable<dict<string, string>> $aw = null;
public static async function lookup(string $key): Awaitable<string> {
// Add this key to the pending batch
self::$pendingKeys[] = $key;
// If there's no awaitable about to start, create a new one
if (self::$aw === null) {
self::$aw = self::go();
}
// Wait for the batch to complete, and get our result from it
$results = await self::$aw;
return $results[$key];
}
private static async function go(): Awaitable<dict<string, string>> {
// Let other awaitables get into this batch
await \HH\Asio\later();
// Now this batch has started; clear the shared state
$keys = self::$pendingKeys;
self::$pendingKeys = vec[];
self::$aw = null;
// Do the multi-key roundtrip
return await multi_key_lookup($keys);
}
}
async function multi_key_lookup(
vec<string> $keys,
): Awaitable<dict<string, string>> {
// lookup multiple keys, but, for now, return something random
$r = dict[];
foreach ($keys as $key) {
$r[$key] = \str_shuffle("ABCDEF");
}
return $r;
}