Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2890769
DoorkeeperFeedWorker.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
5 KB
Referenced Files
None
Subscribers
None
DoorkeeperFeedWorker.php
View Options
<?php
/**
* Publish events (like comments on a revision) to external objects which are
* linked through Doorkeeper (like a linked JIRA or Asana task).
*
* These workers are invoked by feed infrastructure during normal task queue
* operations. They read feed stories and publish information about them to
* external systems, generally mirroring comments and updates in Phabricator
* into remote systems by making API calls.
*
* @task publish Publishing Stories
* @task context Story Context
* @task internal Internals
*/
abstract
class
DoorkeeperFeedWorker
extends
FeedPushWorker
{
private
$publisher
;
private
$feedStory
;
private
$storyObject
;
/* -( Publishing Stories )------------------------------------------------- */
/**
* Actually publish the feed story. Subclasses will generally make API calls
* to publish some version of the story into external systems.
*
* @return void
* @task publish
*/
abstract
protected
function
publishFeedStory
(
)
;
/**
* Enable or disable the worker. Normally, this checks configuration to
* see if Phabricator is linked to applicable external systems.
*
* @return bool True if this worker should try to publish stories.
* @task publish
*/
abstract
public
function
isEnabled
(
)
;
/* -( Story Context )------------------------------------------------------ */
/**
* Get the @{class:PhabricatorFeedStory} that should be published.
*
* @return PhabricatorFeedStory The story to publish.
* @task context
*/
protected
function
getFeedStory
(
)
{
if
(
!
$this
->
feedStory
)
{
$story
=
$this
->
loadFeedStory
(
)
;
$this
->
feedStory
=
$story
;
}
return
$this
->
feedStory
;
}
/**
* Get the viewer for the act of publishing.
*
* NOTE: Publishing currently uses the omnipotent viewer because it depends
* on loading external accounts. Possibly we should tailor this. See T3732.
* Using the actor for most operations might make more sense.
*
* @return PhabricatorUser Viewer.
* @task context
*/
protected
function
getViewer
(
)
{
return
PhabricatorUser
::
getOmnipotentUser
(
)
;
}
/**
* Get the @{class:DoorkeeperFeedStoryPublisher} which handles this object.
*
* @return DoorkeeperFeedStoryPublisher Object publisher.
* @task context
*/
protected
function
getPublisher
(
)
{
return
$this
->
publisher
;
}
/**
* Get the primary object the story is about, like a
* @{class:DifferentialRevision} or @{class:ManiphestTask}.
*
* @return object Object which the story is about.
* @task context
*/
protected
function
getStoryObject
(
)
{
if
(
!
$this
->
storyObject
)
{
$story
=
$this
->
getFeedStory
(
)
;
try
{
$object
=
$story
->
getPrimaryObject
(
)
;
}
catch
(
Exception
$ex
)
{
throw
new
PhabricatorWorkerPermanentFailureException
(
$ex
->
getMessage
(
)
)
;
}
$this
->
storyObject
=
$object
;
}
return
$this
->
storyObject
;
}
/* -( Internals )---------------------------------------------------------- */
/**
* Load the @{class:DoorkeeperFeedStoryPublisher} which corresponds to this
* object. Publishers provide a common API for pushing object updates into
* foreign systems.
*
* @return DoorkeeperFeedStoryPublisher Publisher for the story's object.
* @task internal
*/
private
function
loadPublisher
(
)
{
$story
=
$this
->
getFeedStory
(
)
;
$viewer
=
$this
->
getViewer
(
)
;
$object
=
$this
->
getStoryObject
(
)
;
$publishers
=
id
(
new
PhutilClassMapQuery
(
)
)
->
setAncestorClass
(
'DoorkeeperFeedStoryPublisher'
)
->
execute
(
)
;
foreach
(
$publishers
as
$publisher
)
{
if
(
!
$publisher
->
canPublishStory
(
$story
,
$object
)
)
{
continue
;
}
$publisher
->
setViewer
(
$viewer
)
->
setFeedStory
(
$story
)
;
$object
=
$publisher
->
willPublishStory
(
$object
)
;
$this
->
storyObject
=
$object
;
$this
->
publisher
=
$publisher
;
break
;
}
return
$this
->
publisher
;
}
/* -( Inherited )---------------------------------------------------------- */
/**
* Doorkeeper workers set up some context, then call
* @{method:publishFeedStory}.
*/
final
protected
function
doWork
(
)
{
if
(
PhabricatorEnv
::
getEnvConfig
(
'phabricator.silent'
)
)
{
$this
->
log
(
"%s\n"
,
pht
(
'This software is running in silent mode.'
)
)
;
return
;
}
if
(
!
$this
->
isEnabled
(
)
)
{
$this
->
log
(
"%s\n"
,
pht
(
"Doorkeeper worker '%s' is not enabled."
,
get_class
(
$this
)
)
)
;
return
;
}
$publisher
=
$this
->
loadPublisher
(
)
;
if
(
!
$publisher
)
{
$this
->
log
(
"%s\n"
,
pht
(
'Story is about an unsupported object type.'
)
)
;
return
;
}
else
{
$this
->
log
(
"%s\n"
,
pht
(
"Using publisher '%s'."
,
get_class
(
$publisher
)
)
)
;
}
$this
->
publishFeedStory
(
)
;
}
/**
* By default, Doorkeeper workers perform a small number of retries with
* exponential backoff. A consideration in this policy is that many of these
* workers are laden with side effects.
*/
public
function
getMaximumRetryCount
(
)
{
return
4
;
}
/**
* See @{method:getMaximumRetryCount} for a description of Doorkeeper
* retry defaults.
*/
public
function
getWaitBeforeRetry
(
PhabricatorWorkerTask
$task
)
{
$count
=
$task
->
getFailureCount
(
)
;
return
(
5
*
60
)
*
pow
(
8
,
$count
)
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sun, Jan 19, 14:04 (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1125337
Default Alt Text
DoorkeeperFeedWorker.php (5 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment