39 private const LEGACY_EVENTLOGGING_SCHEMA =
'MediaWikiPingback';
47 private const EVENT_PLATFORM_SCHEMA_ID =
'/analytics/legacy/mediawikipingback/1.0.0';
59 private const EVENT_PLATFORM_STREAM =
'eventlogging_MediaWikiPingback';
62 private const EVENT_PLATFORM_EVENT_INTAKE_SERVICE_URI =
63 'https://intake-analytics.wikimedia.org/v1/events?hasty=true';
93 string $eventIntakeUrl = self::EVENT_PLATFORM_EVENT_INTAKE_SERVICE_URI
101 $this->eventIntakeUri = $eventIntakeUrl;
110 public function run(): void {
115 if ( $this->wasRecentlySent() ) {
119 if ( !$this->acquireLock() ) {
120 $this->logger->debug( __METHOD__ .
": couldn't acquire lock" );
125 if ( !$this->postPingback( $data ) ) {
126 $this->logger->warning( __METHOD__ .
": failed to send; check 'http' log channel" );
132 $dbw = $this->dbProvider->getPrimaryDatabase();
133 $timestamp = ConvertibleTimestamp::time();
134 $dbw->newInsertQueryBuilder()
135 ->insertInto(
'updatelog' )
136 ->row( [
'ul_key' => $this->key,
'ul_value' => $timestamp ] )
137 ->onDuplicateKeyUpdate()
138 ->uniqueIndexFields( [
'ul_key' ] )
139 ->set( [
'ul_value' => $timestamp ] )
140 ->caller( __METHOD__ )->execute();
141 $this->logger->debug( __METHOD__ .
": pingback sent OK ({$this->key})" );
147 private function wasRecentlySent(): bool {
148 $timestamp = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
149 ->select(
'ul_value' )
150 ->from(
'updatelog' )
151 ->where( [
'ul_key' => $this->key ] )
152 ->caller( __METHOD__ )->fetchField();
153 if ( $timestamp ===
false ) {
157 if ( ConvertibleTimestamp::time() - (
int)$timestamp > 60 * 60 * 24 * 30 ) {
171 private function acquireLock(): bool {
172 $cacheKey = $this->cache->makeKey(
'pingback', $this->key );
173 if ( !$this->cache->add( $cacheKey, 1, $this->cache::TTL_HOUR ) ) {
178 $dbw = $this->dbProvider->getPrimaryDatabase();
179 if ( !$dbw->lock( $this->key, __METHOD__, 0 ) ) {
197 $wiki = $this->fetchOrInsertId();
200 'event' => self::getSystemInfo( $this->config ),
201 'schema' => self::LEGACY_EVENTLOGGING_SCHEMA,
207 '$schema' => self::EVENT_PLATFORM_SCHEMA_ID,
208 'client_dt' => ConvertibleTimestamp::now( TS::ISO_8601 ),
214 'stream' => self::EVENT_PLATFORM_STREAM,
235 'PHP' => PHP_VERSION,
236 'OS' => PHP_OS .
' ' . php_uname(
'r' ),
237 'arch' => PHP_INT_SIZE === 8 ? 64 : 32,
238 'machine' => php_uname(
'm' ),
241 if ( isset( $_SERVER[
'SERVER_SOFTWARE'] ) ) {
242 $event[
'serverSoftware'] = $_SERVER[
'SERVER_SOFTWARE'];
245 $limit = ini_get(
'memory_limit' );
246 if ( $limit && $limit !==
"-1" ) {
247 $event[
'memoryLimit'] = $limit;
262 private function fetchOrInsertId(): string {
265 $id = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
266 ->select(
'ul_value' )
267 ->from(
'updatelog' )
268 ->where( [
'ul_key' =>
'PingBack' ] )
269 ->caller( __METHOD__ )->fetchField();
270 if ( $id !==
false ) {
274 $dbw = $this->dbProvider->getPrimaryDatabase();
275 $id = $dbw->newSelectQueryBuilder()
276 ->select(
'ul_value' )
277 ->from(
'updatelog' )
278 ->where( [
'ul_key' =>
'PingBack' ] )
279 ->caller( __METHOD__ )->fetchField();
280 if ( $id !==
false ) {
285 $dbw->newInsertQueryBuilder()
286 ->insertInto(
'updatelog' )
287 ->row( [
'ul_key' =>
'PingBack',
'ul_value' => $id ] )
288 ->caller( __METHOD__ )->execute();
305 private function postPingback( array $data ): bool {
306 $request = $this->http->create( $this->eventIntakeUri, [
308 'postData' => FormatJson::encode( $data ),
310 $request->setHeader(
'Content-Type',
'application/json' );
312 $result = $request->execute();
314 return $result->isGood();