2

i want to send "server sent events" SSE from my yii2 application. when i try this script (without yii2), line after line is being print immediately, each after a one-second pause.

sse.php

<?php

date_default_timezone_set("Europe/Vienna");
header("Content-Type: text/event-stream");
header('X-Accel-Buffering: no');


$i = 0;

while ($i++ < 3) {
    $curDate = date(DATE_ISO8601);
    echo 'data: ' . json_encode(['message' => $curDate]), "\n\n";


    while (ob_get_level() > 0) {
        ob_end_flush();
    }
    flush();


    if (connection_aborted()) {
        break;
    }

    sleep(1);
}

when i try this action (extending yii\base\Controller), the output is being buffered and sent as once, after 3 seconds.

SseController.php

<?php

namespace frontend\controllers;

use Yii;

class SseController extends \yii\base\Controller
{
    public function actionStream()
    {
        $this->layout = false;

        Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
        Yii::$app->response->isSent = true;
        Yii::$app->session->close();

        header('Content-Type: text/event-stream');
        header("Cache-Control: no-cache, must-revalidate");
        header("X-Accel-Buffering: no");


        $i = 0;

        while ($i++ < 3) {
            $curDate = date(DATE_ISO8601);
            echo 'data: ' . json_encode(['message' => $curDate]), "\n\n";

            while (ob_get_level() > 0) {
                ob_end_flush();
            }
            flush();


            if (connection_aborted()) {
                break;
            }

            sleep(1);
        }

        Yii::$app->response->statusCode = 404;
        Yii::$app->response->data = null;
    }
}

So, how can i configure yii's controller to dump raw output immediately, without buffering, to make sse work? sse.php test script is meant to prove that server settings are ok.

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
e-frank
  • 739
  • 11
  • 21

1 Answers1

1

If the problem is only in the Yii, then perhaps this additional will help:

Yii::$app->response->stream = true;

However, both versions of your code worked fine for me locally with Yii2, but did not work on the hosting. This additional helped me:

@ob_end_clean();
ini_set('output_buffering', 0);

Here is the full code of the method if anyone needs it:

public function yourAction() {
    @ob_end_clean();
    ini_set('output_buffering', 0);
    
    header('Content-Type: text/event-stream');
    header("Cache-Control: no-cache, must-revalidate");
    header("X-Accel-Buffering: no");
    
    echo "data: 1\n\n";
    flush();
    
    sleep(1);
    
    echo "data: 2\n\n";
    flush();
}
vodevel
  • 144
  • 4