もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

相棒の猫が天国に行った

こんばんは。

特に記述的な話ではありません。

先日、自分が飼っていた猫が天に召されました。

猫は死に目を見せないというのは本当で、当日夜寝るまで、全くそんな素振りも見せず、ホットカーペットの上で、幸せそうにゴロゴロ喉を鳴らしていたんですが、朝起きると、パタリとしておりました。

トイレやおしっこも、全く普通で、吐く頻度や、吐くものも特に変わりなかったので、予兆に気づいてあげられませんでした。

その後、以下のサイト経由でペット火葬を申込をしました。

petlly.jp

24時間対応とはいえ早朝5時とかだから、対応難しいかなー?と思ってたんですが、快く対応してくれました。

10年というちょっと短い期間でしたが、とても充実した10年でした!

天国行っても腹減ったー!

と元気に鳴いててほしいです!

f:id:kojirooooocks:20210131165832j:plain f:id:kojirooooocks:20210131165842j:plain f:id:kojirooooocks:20210131165858j:plain f:id:kojirooooocks:20210131165909j:plain f:id:kojirooooocks:20210131165919j:plain f:id:kojirooooocks:20210131165929j:plain f:id:kojirooooocks:20210131165938j:plain f:id:kojirooooocks:20210131165948j:plain f:id:kojirooooocks:20210131170052j:plain f:id:kojirooooocks:20210131170100j:plain f:id:kojirooooocks:20210131170111j:plain f:id:kojirooooocks:20210131170219j:plain f:id:kojirooooocks:20210131170227j:plain f:id:kojirooooocks:20210131170235j:plain f:id:kojirooooocks:20210131170245j:plain f:id:kojirooooocks:20210131170252j:plain f:id:kojirooooocks:20210131170300j:plain f:id:kojirooooocks:20210131170345j:plain f:id:kojirooooocks:20210131170349j:plain f:id:kojirooooocks:20210131170359j:plain f:id:kojirooooocks:20210131170408j:plain

circleCIを並列実行して、実行時間を短縮する

はじめに

こんばんは。

今回は、circleCIの実行時間を短縮した備忘録です。

テストコードが多くなると、ciでテストを回すのにかなりの時間がかかります。

ぼくがお仕事を頂いている企業様でも12〜15分(テストのjobは8〜10分)程度の実行時間でした。

ここに課題を感じていたので、ciの並列実行を行い、実行時間の短縮を目指しました。

参考サイト

本題

キモとなるのは parallelism になります。

今回 parallelism で指定した数分、コンテナが並列で実行されます。

こちらを6に指定して、並列で6台が実行されるように変更しました。

並列で実行されるにあたり、各コンテナで実行されるテストを指定してあげる必要がありました。

それを可能にするのが circleci tests globcircleci tests split になります。

glob で実行したいテストのパスを取得し、 split でコンテナ毎に振り分けます。

以下のような感じです。

circleci tests glob "./tests/TestCase/**/*Test.php" | circleci tests split

また、 split によってコンテナ毎に実行してほしいテストのパスが振り分けられますが、これを phpunitで実行するために、 phpunitxmlをつくってあげます。

circleci tests glob "./tests/TestCase/**/*Test.php" | circleci tests split | xargs php ./generateXml.php

generateXml.php

<?php

$basePath = '/home/circleci/project';
$files = array_slice($argv, 1);
$xmlFileStringData = [];
foreach ($files as $file) {
    $xmlFileStringData[] = "<file>{$basePath}/{$file}</file>";
}
$testFileString = implode("\n", $xmlFileStringData);
$template = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="{$basePath}/tests/bootstrap.php">
    <testsuites>
        <testsuite name="Test Suite">
            {$testFileString}
        </testsuite>
    </testsuites>
</phpunit>
XML;

file_put_contents("/tmp/ci_phpunit.xml", $template);

generateXml.php で作成したxmlファイルを指定して、phpunitを実行します

./vendor/bin/phpunit --configuration /tmp/ci_phpunit.xml

これで、コンテナ毎に割り当てられたテストをphpunitが実行してくれます。

実行すると、こんな感じで、コンテナが parallelism の数分実行してくれます。

f:id:kojirooooocks:20210117234927p:plain

つなげて書くと以下みたいな感じです。

      - run:
          name: Execute UnitTest
          command: |
            circleci tests glob "./tests/TestCase/**/*Test.php" | circleci tests split | xargs php ./generateXml.php
            ./vendor/bin/phpunit --configuration /tmp/ci_phpunit.xml
      - store_artifacts:
          name: Store Artifact
          path: logs/cli-error.log

テスト実行時にエラーログを artifactに登録されるようにしているのですが、そちらも複数のコンテナ毎に登録されます。

f:id:kojirooooocks:20210117234940p:plain

今回の対応で、実行時間を大体5〜6分に抑えることができました。

また、resource classをデフォルトの mediumからsmallに落とすことで、並列実行しつつ消費クレジットも落とすことができました。

終わりに

結果的には大成功という感じでした。

他にも 歴史のあるレポジトリのため chckoutに1分程度時間がかかっているので、そこを shallow cloneなどを用いてあげれば、更に短縮が見込めそうです。

現場からは以上です。

php8を試してみた

はじめに

こんばんは。

緊急事態宣言でましたね。

ぼくは、以前同様家族で引きこもる形になると思います。

今回は触ろう触ろうと思って触ってなかったphp8を触ってみます。

phpマニュアルみながら、「使いそうだな〜」と思った機能を厳選して触ってみます。

本題

名前付き引数

引数が何個も多いようなメソッドや関数で、他の引数は別に指定しなくていいんだけど、ここの引数だけ指定したいみたいなニーズあると思うのですが、そんなときにこれ便利ですね。

<?php
function fn_example(?int $foo = null, ?int $bar = null, ?int $baz = null, ?string $hoge = null, ?string $fuga = null) {
        var_dump($foo);
        var_dump($bar);
        var_dump($baz);
        var_dump($hoge);
        var_dump($fuga);
}

# php8未満
fn_example(null, null, null, null, 'aaaaa');

# php8以降
fn_example(fuga: 'aaaaa')

/*
> # php example1.php
NULL
NULL
NULL
NULL
string(5) "aaaaa"
*/

アトリビュート

読んだときに、アノテーションとどう違うのかよくわからなかったのですが、こちらのブログで解説されていました。

パフォーマンスの向上

アノテーションの Doc コメントは文字列で取得することしか出来ず、パースするのに時間がかかります。そのため doctrine/annotations では一度取得したアノテーションをキャッシュすることが可能になっています。 Attributes の形式だと Reflection から取得出来るようになるので、パースの時間を省略することが出来ます。

取得容易性の向上

ReflectionClass::getAttributes() などのメソッドで、 Reflection から簡単に Attributes を取り出せるようになったので、 Doc コメントアノテーションに比べ取得が格段に簡単になります。

明確な型インスタンス

Attribute::newInstance() メソッドを使って Attribute クラスのインスタンスを生成することが出来るため、明確な型を使って利用ロジックを実装することが出来ます。そのため、静的解析やIDE補完などが容易に行えるようになります。

PHP Core や Extensions での利用

PHP拡張の実装時に Attributes を使うことによって、拡張機能により実装された Attributes をアプリケーションコードに落とし込むことが出来るようになります。

個人的には パフォーマンスの向上と取得容易性の向上がアツいと思いました。

php マニュアルそのまま試してみましたが、まだ、実際の実装時にどこまで活用していけるかは想像できていません。

<?php

#[Attribute]
class MyAttribute
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }
}

#[MyAttribute(value: 1234)]
class Thing
{
}

function dumpAttributeData($reflection) {
    $attributes = $reflection->getAttributes();

    foreach ($attributes as $attribute) {
       var_dump($attribute->getName());
       var_dump($attribute->getArguments());
       var_dump($attribute->newInstance());
    }
}

dumpAttributeData(new ReflectionClass(Thing::class));
/*
string(11) "MyAttribute"
array(1) {
  ["value"]=>
  int(1234)
}
object(MyAttribute)#3 (1) {
  ["value"]=>
  int(1234)
}
*/

コンストラクタのプロモーション

クラスのコンストラクタで引数をもらって、その引数をプロパティに詰め替えるとかってよくやってると思いますが、それがぐんと簡単になります。

<?php

# php8未満
class Foo
{
    public function __construct(int $aaa, int $bbb, int $ccc, int $ddd, int $eee)
    {
        $this->aaa = $aaa;
        $this->bbb = $bbb;
        $this->ccc = $ccc;
        $this->ddd = $ddd;
        $this->eee = $eee;
    }

    public function toArray(): array
    {
        return [
            $this->aaa,
            $this->bbb,
            $this->ccc,
            $this->ddd,
            $this->eee,
        ];
    }
}

# php8以降
class Foo
{
    public function __construct(
        private int $aaa, 
        private int $bbb, 
        private int $ccc, 
        private int $ddd, 
        private int $eee
    ){}

    public function toArray(): array
    {
        return [
            $this->aaa,
            $this->bbb,
            $this->ccc,
            $this->ddd,
            $this->eee,
        ];
    }
}



$foo = new Foo(10, 20, 30, 40, 50);
var_dump($foo->toArray());

/*
# php example3.php
array(5) {
  [0]=>
  int(10)
  [1]=>
  int(20)
  [2]=>
  int(30)
  [3]=>
  int(40)
  [4]=>
  int(50)
}
*/

union型

int か floatで来るみたいなときに、どっちにも対応したいからとりあえず stringでみたいな逃げ方をしなくても良くなります。

<?php
class Item {
    private int|float $rate;

    public function __construct(private string $itemName, private int $price) {}

    public function setRate(int|float $rate): void
    {
        $this-> rate = $rate;
    }
    
    public function calc(): int|float
    {
       return $this->price * $this->rate;
    }
}

$item1 = new Item("toybox1", 50);
$item1->setRate(10);
var_dump($item1->calc());

$item2 = new Item("toybox2", 55);
$item2->setRate(8.9);
var_dump($item2->calc());

/*
# php example4.php
int(500)
float(489.5)
*/

match式

switchに似てますが、より厳密によりシンプルに書けるみたいです。 match式が出てきたことにより match予約語になってます。

<?php

$type = 'red';

echo match ($type) {
    'blue'   => 'BLUE',
    'green'  => 'GREEN',
    'red'    => 'RED',
    'yellow' => 'YELLOW',
};

> RED

switchだとネストも激しくなるし、あと厳格な比較ができないのが難点だったので、ifを多用していたのですが、これですごくシンプルにかけます。

nullsafe 演算子

個人的に激アツ機能です。 取得先のオブジェクトがnullでメソッドチェーンでつなげてやってしまい、 PHP Fatal error: Uncaught Error: Call to a member function xxxx() on null みたいなってめちゃめちゃ経験ありますよね。。 if文で大体回避するかもしれませんが、それを解消してくれます。 ただ、多様してると追いにくくなりそうな気もしていますので、使い所は気をつけないとと思いました。

<?php

class User
{
    public function __construct(private string $name, private int $age){}

    public function name(): string
    {
        return $this->name;
    }
}

class UserRepository
{
    private array $userList = [
        1 => ['name' => 'AAA', 'age' => 30],
        2 => ['name' => 'BBB', 'age' => 35],
    ];

    public function findUser(int $id): ?User
    {
        if (!isset($this->userList[$id])) {
            return null;
        }

        return new User(
            $this->userList[$id]['name'],
            $this->userList[$id]['age'],
        );
    }
}

$repository = new UserRepository();
var_dump($repository->findUser(1)?->name());
var_dump($repository->findUser(2)?->name());
var_dump($repository->findUser(3)?->name());

/*
# php example6.php
string(3) "AAA"
string(3) "BBB"
NULL
*/

throw が式として使える

地味に嬉しい機能でした。 シンプルに書けるようになります。

例えば試してないけど、こんな感じにもかけるのかな?

<?php
$this->User->save();
$userId = $this->User->getLastInsertId() ?? throw new UserRegisterException('ユーザーを登録できませんでした。');

str_contains()の実装

文字列が含まれているかを調べる関数です。

もともと php8未満でも再現可能ですが、専用の関数としてできて扱いやすくなった印象ですかね?

var_dump(str_contains("初めまして!! Kojirockですよ!", "Kojirock")); // true
var_dump(str_contains("初めまして!! Kojirockですよ!", "kojikoji")); // false

終わりに

ほかにも新機能色々とあるみたいなのですが、個人的に使いやすそうなのをピックアップしてみました。

php7 -> php8のバージョンアップはそこまで苦ではないと思いますが、使用しているFWのバージョンアップのほうが鬼門ですよね。

現場からは以上です。

2021年の目標

はじめに

こんばんは。

あけましておめでとうございます。

今回のブログでは今年1年の目標を立てておきたいと思います。

去年の目標立てたブログって合ったかな?と思ったらありました。

kojirooooocks.hatenablog.com

すごくざっくりした目標でした...w

今回は前回の総括から目標を立てたいと思います。

本題

1. ブログ数は年間76件を目指す

という感じで、合計75件を目指そうと思います。

2. アドベントカレンダー参加数は4件を目指す

一人アドベントカレンダー + その他のアドベントカレンダーを3件という感じで合計4件を目指します。

3. OSSの貢献数12件を目指す

ドキュメント更新やテスト追加など簡単なものでもいいので 月1で good first issue あたりを月に1件さばくことを目指そうと思います。

4. 積本を12冊読破する

毎回読まずに新たな本を買っているので、今回は年間12冊という感じで月に1冊必ず積本を読破するように目指します。

5. LTを2回以上行う

去年の目標でも立てましたが、LTやりたいなとおもいます。

多分今年もオンライン開催が主だと思うので、ハードルも少し下がってるので、ぜひやりたいです。

6. 積ゲームを12本クリアする

これも積本と同じなんですが、買うだけ買ってやってないゲームが20本くらいあるので、月に1本クリアしようと思いますw

ちなみに、この年末年始で Last of Us2と、バイオ3をクリアしたので、今月分はクリアですw

BIOHAZARD RE:3 Z Version 【CEROレーティング「Z」】

BIOHAZARD RE:3 Z Version 【CEROレーティング「Z」】

  • 発売日: 2020/04/03
  • メディア: Video Game

【PS4】The Last of Us Part II 【CEROレーティング「Z」】

【PS4】The Last of Us Part II 【CEROレーティング「Z」】

  • 発売日: 2020/06/19
  • メディア: Video Game

7. 10kgの減量を行う

月1kgといいたいところだけど、それは流石に無理そうだから、ちょっと甘めに設定しました。

終わりに

こんな感じで仕事とプライベート混ざった目標になりましたが、以上です。

今年も頑張るぞ!!

2020年の雑な総括

はじめに

こんばんは。

年の瀬になり、2020年を雑に振り返りたいと思います。

本題

ブログ数は合計51件

kojirooooocks.hatenablog.com

今年は12月の一人アドベントカレンダーをやることがなかったので、去年・一昨年よりも記事数が少なくなってしまいました。

アドベントカレンダーの参加数は2件

kojirooooocks.hatenablog.com

kojirooooocks.hatenablog.com

今年は今お世話になっている会社のアドベントカレンダーの貢献のために書いた2件のみでした。

11月12月は仕事が忙しく書きだめることも出来ず今年はこれだけで断念しました。

OSSの貢献数は1件

kojirooooocks.hatenablog.com

ドキュメントの貢献が1件のみで今年はダメダメでした...

積本が増え続けてる

今もとんでもない量の積本があり、全然読めていないです...

インプットもアウトプットも雑な1年だった

今年は一年を通して雑な一年になってしまいました。

今年の前半で自分の出来なさに絶望してそこからなんとか、這い上がっていくために食らいついていきましたが、前半の絶望テンションが続いているのか消極的な行動になっていました。

終わりに

ざっくり雑な総括になりましたが、こんな感じで、自分的にはダメダメな1年でした。

来年はちょっと気を引き締めて、いい1年にしていきたいと思います。

現場からは以上です。

Blimp を試した

参考サイト

はじめに

こんばんは。

今回は参考サイトをみて、ワクワクしたので、 Blimpを試してみました。

Blimpって飛行船って意味なんですね。

だからロゴが飛行船なのか。

まぁそれはいいや。

本題

インストール

$ brew install kelda/tools/blimp
$ brew link blimp

blimpログイン

blimp loginを実行すると ブラウザでログインページが表示されるので、ログインすると Successfully loggedになります。

f:id:kojirooooocks:20201227225513p:plain

$ blimp login
Blimp will be shutting on Dec 15, 2020. Migrate to the self-hosted version (https://blimpup.io/docs/#/cluster-setup) to keep using it.
Your browser has been opened to log in.
Please leave this command running while you finish logging in.
If your browser doesn't open, you can also visit this link directly:


Successfully logged in

アプリケーション実行

アプリケーションは @ucan_labさんの docker-laravelを使わせてもらいました。

$ git clone git@github.com:ucan-lab/docker-laravel.git blimp-example
$ cd blimp-example
$ cp .env.example .env
$ composer create-project --prefer-dist "laravel/laravel=7.*" backend
$ cd backend
$ php artisan key:generate
$ cd ../
$ blimp up
.
..
...
Blimp will be shutting on Dec 15, 2020. Migrate to the self-hosted version (https://blimpup.io/docs/#/cluster-setup) to keep using it.
Booting cloud sandbox  
Deploying Docker Compose file to sandbox  
app     Running
db      Running
web     Running
All containers successfully started

確認

localhostにアクセスします。

f:id:kojirooooocks:20201227225528p:plain

キャッシュでエラーになるので、コンテナ内に入りstorageに権限を与えます。

$ blimp ssh app
$ chmod -R 777 storage

f:id:kojirooooocks:20201227225543p:plain

表示されました!

DBにもコンテナがあり、migrationsも実行できます。

$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.09 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.07 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.04 seconds)

終わりに

exposeとかで公開もできます。 ただ、security面はどうなんだろうとちょっと思ったりもします。

限定公開するという点では、最悪basic認証を自分で無理やりかけられる ngrok がまだ自分的に使いやすいかもしれません。

現場からは以上です。

digdag + embulk で bigQueryを差分更新

はじめに

こんばんは。

前回の記事から embulkで遊んでるのですが、 bigQueryにデータを同期させる際に、 更新されたデータのみ 同期させたい場合はどうすればいいのだろう?と色々探していると、参考サイトをみつけました。

さっそくやってみます。

参考サイト

本題

前提

データは前回のデータを使います。

> select * from users;
+----+-------+---------------------+---------------------+
| id | name  | created             | modified            |
+----+-------+---------------------+---------------------+
|  1 | test  | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  2 | test2 | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  3 | test3 | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  4 | test4 | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  5 | test5 | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
+----+-------+---------------------+---------------------+
5 rows in set (0.00 sec)

bigQuery側もこんな感じで同期しています。日付だけUTCでずれちゃってますが...

f:id:kojirooooocks:20201212040649p:plain

1. digdagのインストール

インストール

$ brew install digdag
$ digdag --version
0.9.42

プロジェクト作成

$ digdag init example_bigquery
$ digdag init example_bigquery
2020-12-11 01:09:00 +0900: Digdag v0.9.42
  Creating example_bigquery/example_bigquery.dig
  Creating example_bigquery/.gitignore
Done. Type `cd example_bigquery` and then `digdag run example_bigquery.dig` to run the workflow. Enjoy!


# ディレクトリが掘られちゃうので、一旦上に持っていきます。
$ mv example_bigquery/example_bigquery.dig ./
$ mv example_bigquery/.gitignore ./
$ rm -rf example_bigquery

digファイル作成

+uploads:
  sh>: embulk run users.yml.liquid
 
+merge_task:
  sh>: bq query --batch --replace=true --use_legacy_sql=false --project_id=XXXXXXX --location=asia-northeast1 --destination_table='dataset_example1.users' "$(cat ./merge.sql)"

2. Google Cloud SDK のインストール

こちらからDownload後、インストールする

3. embulkファイルの更新

{% include 'env' %}
in:
  type: mysql
  host: {{ in_host }}
  user: {{ in_user }}
  password: {{ in_password }}
  database: {{ in_database }}
  table: users
  where: "modified > DATE_SUB(CURDATE(), INTERVAL 1 DAY)"  ← ここを追加
out:
  type: bigquery
  mode: replace
  table: tmp_users  ← ここをusersからtmp_usersに変更
  auth_method: json_key
  json_keyfile:  {{ out_json }}
  project: {{ out_project }}
  dataset: {{ out_dataset }}
  location: asia-northeast1
  compression: GZIP
  auto_create_dataset: true
  auto_create_table: true

4. merge用SQLファイル作成

参考サイトをコピーさせてもらいました。

SELECT * EXCEPT(rn) FROM (
    SELECT *, row_number() over (PARTITION BY id ORDER BY modified DESC) AS rn
    FROM (SELECT * FROM dataset_example1.tmp_users UNION ALL SELECT * FROM dataset_example1.users)
) WHERE rn = 1

5. 差分データを作成する

embulkの inwhere に引っかかるように、 modifiedが昨日よりあとの日にち になるようにデータを更新します。

mysql> UPDATE users SET name = 'AAAAAAAAAAAA', modified = '2020-12-12 00:00:00' WHERE id = 3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from users;
+----+--------------+---------------------+---------------------+
| id | name         | created             | modified            |
+----+--------------+---------------------+---------------------+
|  1 | test         | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  2 | test2        | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  3 | AAAAAAAAAAAA | 2020-12-01 00:00:00 | 2020-12-12 00:00:00 |
|  4 | test4        | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
|  5 | test5        | 2020-12-01 00:00:00 | 2020-12-01 00:00:00 |
+----+--------------+---------------------+---------------------+
5 rows in set (0.00 sec)

id: 3の nameを変更しました。

6. 実行する

$ digdag run example_bigquery.dig
...
+----+--------------+---------------------+---------------------+
| id |     name     |       created       |      modified       |
+----+--------------+---------------------+---------------------+
|  1 | test         | 2020-11-30 15:00:00 | 2020-11-30 15:00:00 |
|  5 | test5        | 2020-11-30 15:00:00 | 2020-11-30 15:00:00 |
|  4 | test4        | 2020-11-30 15:00:00 | 2020-11-30 15:00:00 |
|  2 | test2        | 2020-11-30 15:00:00 | 2020-11-30 15:00:00 |
|  3 | AAAAAAAAAAAA | 2020-11-30 15:00:00 | 2020-12-11 15:00:00 |
+----+--------------+---------------------+---------------------+
...
Success. Task state.

いったみたいです。

bigQueryを確認します。

f:id:kojirooooocks:20201212040724p:plain

id: 3の内容が更新されていました!

全体の流れは、参考にさせていただいたメルカリさんのブログで詳しく解説されています。

(1) BigQuery上に対象テーブルのitems と 一時テーブルの tmp_items があります

(2) UNION ALL で全行の和集合を構成します。

(3) row_number() over (PARTITION BY id ORDER BY updated DESC) によって itemsのid毎に更新日の降順でグループ分けします。(右下が拡大図です)

(4) row_number = rd が 1 のものだけをSELECTします。その際に作業用カラムrnをEXCEPT(rn)によって除去します

終わりに

参考サイトのおかげで、結構簡単に差分更新を実現することが出来ました。

一点悩んだこととしては、 今回 bigQueryにクエリを発行する際 shellscriptで実行したのですが、 digdagの bq> でも本来は実行できるようでした。

ただ、僕の場合、 bq>だと何回やっても not foundエラーが出てしまっていたので、仕方なく shellscriptで実行しました。

たぶん、locationの指定が出来てないので not foundとかになってるのかな?とか思ってるのですが、 bq> を使う場合の location設定がわからず断念しました...

どなたか知っていたら教えて下さい。

現場からは以上です。