52 private const LEGACY_EVENTLOGGING_SCHEMA =
'MediaWikiPingback';
60 private const EVENT_PLATFORM_SCHEMA_ID =
'/analytics/legacy/mediawikipingback/1.0.0';
72 private const EVENT_PLATFORM_STREAM =
'eventlogging_MediaWikiPingback';
75 private const EVENT_PLATFORM_EVENT_INTAKE_SERVICE_URI =
76 'https://intake-analytics.wikimedia.org/v1/events?hasty=true';
106 string $eventIntakeUrl = self::EVENT_PLATFORM_EVENT_INTAKE_SERVICE_URI
114 $this->eventIntakeUri = $eventIntakeUrl;
123 public function run(): void {
128 if ( $this->wasRecentlySent() ) {
132 if ( !$this->acquireLock() ) {
133 $this->logger->debug( __METHOD__ .
": couldn't acquire lock" );
138 if ( !$this->postPingback( $data ) ) {
139 $this->logger->warning( __METHOD__ .
": failed to send; check 'http' log channel" );
145 $dbw = $this->dbProvider->getPrimaryDatabase();
146 $timestamp = ConvertibleTimestamp::time();
147 $dbw->newInsertQueryBuilder()
148 ->insertInto(
'updatelog' )
149 ->row( [
'ul_key' => $this->key,
'ul_value' => $timestamp ] )
150 ->onDuplicateKeyUpdate()
151 ->uniqueIndexFields( [
'ul_key' ] )
152 ->set( [
'ul_value' => $timestamp ] )
153 ->caller( __METHOD__ )->execute();
154 $this->logger->debug( __METHOD__ .
": pingback sent OK ({$this->key})" );
162 private function wasRecentlySent(): bool {
163 $timestamp = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
164 ->select(
'ul_value' )
165 ->from(
'updatelog' )
166 ->where( [
'ul_key' => $this->key ] )
167 ->caller( __METHOD__ )->fetchField();
168 if ( $timestamp ===
false ) {
172 if ( ConvertibleTimestamp::time() - (
int)$timestamp > 60 * 60 * 24 * 30 ) {
186 private function acquireLock(): bool {
187 $cacheKey = $this->cache->makeKey(
'pingback', $this->key );
188 if ( !$this->cache->add( $cacheKey, 1, $this->cache::TTL_HOUR ) ) {
193 $dbw = $this->dbProvider->getPrimaryDatabase();
194 if ( !$dbw->lock( $this->key, __METHOD__, 0 ) ) {
212 $wiki = $this->fetchOrInsertId();
215 'event' => self::getSystemInfo( $this->config ),
216 'schema' => self::LEGACY_EVENTLOGGING_SCHEMA,
222 '$schema' => self::EVENT_PLATFORM_SCHEMA_ID,
223 'client_dt' => ConvertibleTimestamp::now( TS_ISO_8601 ),
229 'stream' => self::EVENT_PLATFORM_STREAM,
250 'PHP' => PHP_VERSION,
251 'OS' => PHP_OS .
' ' . php_uname(
'r' ),
252 'arch' => PHP_INT_SIZE === 8 ? 64 : 32,
253 'machine' => php_uname(
'm' ),
256 if ( isset( $_SERVER[
'SERVER_SOFTWARE'] ) ) {
257 $event[
'serverSoftware'] = $_SERVER[
'SERVER_SOFTWARE'];
260 $limit = ini_get(
'memory_limit' );
261 if ( $limit && $limit !==
"-1" ) {
262 $event[
'memoryLimit'] = $limit;
277 private function fetchOrInsertId(): string {
280 $id = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
281 ->select(
'ul_value' )
282 ->from(
'updatelog' )
283 ->where( [
'ul_key' =>
'PingBack' ] )
284 ->caller( __METHOD__ )->fetchField();
285 if ( $id !==
false ) {
289 $dbw = $this->dbProvider->getPrimaryDatabase();
290 $id = $dbw->newSelectQueryBuilder()
291 ->select(
'ul_value' )
292 ->from(
'updatelog' )
293 ->where( [
'ul_key' =>
'PingBack' ] )
294 ->caller( __METHOD__ )->fetchField();
295 if ( $id !==
false ) {
300 $dbw->newInsertQueryBuilder()
301 ->insertInto(
'updatelog' )
302 ->row( [
'ul_key' =>
'PingBack',
'ul_value' => $id ] )
303 ->caller( __METHOD__ )->execute();
320 private function postPingback( array $data ): bool {
321 $request = $this->http->create( $this->eventIntakeUri, [
323 'postData' => FormatJson::encode( $data ),
325 $request->setHeader(
'Content-Type',
'application/json' );
327 $result = $request->execute();
329 return $result->isGood();