オンライン実験 (oTree) で時間内にマッチングが成立しなかった場合に自動で別のメッセージを出す方法

統計・資料

クラウドソーシングサービス×oTreeでのオンライン実験

普段から私は、クラウドソーシングサービスとoTreeで作った実験プログラムを使ってオンライン実験をしています。クラウドソーシングサービスで参加者を募集してoTreeでの実験プログラムへのリンクにアクセスしてもらい、実験プログラムの最後に表示されるコードを入力してもらうことで謝礼を支払います。つまり、参加者の募集と謝礼の支払いをクラウドソーシングサービスで、実験課題と入力用コードの表示をoTreeで行っているということです。

マッチング不成立問題

しかし、グループで相互作用ををするタイプの実験をするときに、困ることがあります。それは、なかなか参加者のマッチングが成立しない場合があることです。例えば、4人グループで行う実験で最後の一人がなかなか来ないと、先に来た3人は実験課題が始められず、ずっと待つことになってしまうわけです。

その対策として、以前はマッチング待機画面を用意して「5分以上マッチングが成立しない場合は連絡してください、謝礼をお渡しするためのコードを送ります」とお伝えしていたのですが、必要以上に連絡をお願いするのもよくないですし、手動だと安定しないので、自動で謝礼支払い用のコードが表示されるようにしました。

画面見本

※ 静止画だとわからないですが、黒丸部分がアニメーションになっていて、動きます。

方法: 時間が経過したらメッセージを表示するJavescriptのついたWaitページを用意する

matchingWait.html

oTreeで使うテンプレートとして、こちらのコードをmatchingWait.htmlとして追加します。

static→templatesの中に新しいhtmlファイルmatchingWait.htmlを追加します。

{{ block content }}
<div id="wait-text">
    他の参加者が来るのを待っています。5分経っても4人の参加者がマッチングしなかった場合は、謝礼をお渡しするためのコードを自動で表示します。
</div>
<div class="spinner" id="spinner">
    <div class="double-bounce1"></div>
    <div class="double-bounce2"></div>
</div>
<script type="text/javascript">
    function startCountdown() {
        var countdownEnd = localStorage.getItem('countdownEnd');
        if (!countdownEnd) {
            countdownEnd = Date.now() + 5* 60 * 1000; // 5分後のタイムスタンプを保存
            localStorage.setItem('countdownEnd', countdownEnd);
        }

        var interval = setInterval(function() {
            var now = Date.now();
            var timeLeft = countdownEnd - now;

            if (timeLeft <= 0) {
                clearInterval(interval);
                clearInterval(refreshInterval); // リフレッシュを停止
                document.getElementById('wait-text').innerText = '5分以内にマッチングしませんでした。【数字】0000 をクラウドソーシング側にご入力いただければ、謝礼をお支払いします。入力後、こちらの画面は閉じていただいて構いません。この度は誠にありがとうございました。';
                document.getElementById('spinner').style.display = 'none'; // アニメーションを停止
                localStorage.removeItem('countdownEnd');
            }
        }, 1000);
    }

    // ページがリロードされてもタイマーを保持
    startCountdown();

    // 5秒ごとにページをリフレッシュ
    var refreshInterval = setInterval(function() {
        location.reload();
    }, 5000);
</script>

<style>
    .spinner {
        width: 40px;
        height: 40px;
        position: relative;
        margin: 100px auto;
    }

    .double-bounce1, .double-bounce2 {
        width: 100%;
        height: 100%;
        border-radius: 50%;
        background-color: #333;
        opacity: 0.6;
        position: absolute;
        top: 0;
        left: 0;
        -webkit-animation: sk-bounce 2.0s infinite ease-in-out;
        animation: sk-bounce 2.0s infinite ease-in-out;
    }

    .double-bounce2 {
        -webkit-animation-delay: -1.0s;
        animation-delay: -1.0s;
    }

    @-webkit-keyframes sk-bounce {
        0%, 100% { -webkit-transform: scale(0.0) }
        50% { -webkit-transform: scale(1.0) }
    }

    @keyframes sk-bounce {
        0%, 100% { 
            transform: scale(0.0);
            -webkit-transform: scale(0.0);
        } 50% { 
            transform: scale(1.0);
            -webkit-transform: scale(1.0);
        }
    }
</style>
{{ endblock }}

ポイントは、5秒おきにリフレッシュしているところです。これをしないと、マッチングが成立したのにも関わらず画面がこのページのまま自動で切り替わらないという問題が起こりました。

また、<style>~<style>の部分は、待っているときのアニメーションを表示させるためだけのコードなので、別になくてもいいです(上の画面見本の黒い〇の部分です)。

iniy.py Pages部分での設定

作ったテンプレートを読み込むように設定しています。

# PAGES

class matchingWait(WaitPage):

    def is_displayed(player):

        return player.round_number == 1

    template_name = 'matchingWait.html'

    def after_all_players_arrive(group: Group):

懸念点: サーバーへの負荷

懸念点として、「5秒ごとにリフレッシュする」という動作がどれくらいサーバーに負担をかけるのかがわかっていません。

少なくともこの間の実験では、Herokuサーバーの
dyno: Standard x2
Postgress Standard 7
同時接続: 100人
で、問題はありませんでした。

コメント

タイトルとURLをコピーしました