Updated: Comment #N

Problem/Motivation

The CronController class still just calls drupal_cron_run(). We should ideally update this with OO code.

Proposed resolution

Convert drupal_cron_run() to a service, and use that instead in the controller. Projects like elysia_cron can then just switch this service out and be done with it. simple.

Remaining tasks

Patch, unit tests.

User interface changes

None

API changes

No more drupal_cron_run().

Comments

damiankloip’s picture

StatusFileSize
new10.04 KB

Here is a start on this.

dawehner’s picture

Status: Active » Needs review
  1. +++ b/core/lib/Drupal/Core/Cron.php
    @@ -0,0 +1,136 @@
    +    $original_user = $GLOBALS['user'];
    +    $GLOBALS['user'] = drupal_anonymous_user();
    

    oh, can we clean this up?

  2. +++ b/core/modules/system/lib/Drupal/system/CronController.php
    @@ -22,8 +23,8 @@ class CronController {
    +    // @todo inject this as a service?
    

    ?Yes?

Status: Needs review » Needs work

The last submitted patch, 1: 2169267.patch, failed testing.

damiankloip’s picture

Status: Needs work » Needs review
StatusFileSize
new17.54 KB
new8.9 KB

Talked about this on IRC, to chance the user nicely, we may need to look at another follow up issue to allow this, as it's kind of it's own problem.

Converted the rest of the drupal_cron_run() usage and injected things.

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/Cron.php
    @@ -0,0 +1,136 @@
    +  /**
    +   *
    +   */
    ...
    +  /**
    +   * @var \Drupal\Core\Extension\ModuleHandlerInterface
    +   */
    +  protected $moduleHandler;
    +
    +  /**
    +   * @var \Drupal\Core\Lock\LockBackendInterface
    +   */
    +  protected $lock;
    +
    +  /**
    +   * @var \Drupal\Core\Queue\QueueFactory
    +   */
    +  protected $queueFactory;
    +
    +  /**
    +   * @var \Drupal\Core\KeyValueStore\StateInterface
    +   */
    +  protected $state;
    +
    ...
    +/**
    + * @todo
    + */
    

    We usually try to document a bit more.

  2. +++ b/core/lib/Drupal/Core/Cron.php
    @@ -0,0 +1,136 @@
    +    // Force the current user to anonymous to ensure consistent permissions on
    +    // cron runs.
    +    $original_user = $GLOBALS['user'];
    +    $GLOBALS['user'] = drupal_anonymous_user();
    +
    

    It would be great to at least at a todo. In additional we could at least get the current user from the container.

  3. +++ b/core/modules/locale/locale.module
    @@ -386,7 +386,7 @@ function locale_themes_disabled($themes) {
    + * @see \Drupal\Core\Cron
    ...
    - * @see drupal_cron_run()
    

    This @see is quite pointless to be honest, this is just hook_cron implementation. if you want to understand more, look into hook_cron.

damiankloip’s picture

StatusFileSize
new17.7 KB
new1.18 KB

Made those docs changes and rerolled after the context/config patch.

I didn't change the user stuff yet. There seems like not much point in doing that right now? As it will not change the user anyway. Added a todo for that (missed it from the interdiff, sorry, just realised!).

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

This is indeed something which have to tackle in a an additional issue (which is not a follow up technically).

tim.plunkett’s picture

Is it worth writing a unit test?

  1. +++ b/core/lib/Drupal/Core/Cron.php
    @@ -0,0 +1,146 @@
    +  /**
    +   *
    +   */
    

    Missing param doc blocks

  2. +++ b/core/lib/Drupal/Core/Cron.php
    @@ -0,0 +1,146 @@
    +    // @todo This currently does not work, as it will affect the current user
    +    //   being injected into services.
    +    $original_user = $GLOBALS['user'];
    +    $GLOBALS['user'] = drupal_anonymous_user();
    ...
    +    $GLOBALS['user'] = $original_user;
    

    Um, whaaaat? I guess the bottom line should have a @todo as well. Is this what is causing #2108623: Installing via the UI no longer logs in user 1 every time?

damiankloip’s picture

Thanks, will fix those.

damiankloip’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new18.23 KB
new1.75 KB

Ok, updated the constructor docblock, and added the @todo near the end of the run() method.

I would prefer not to unit test this right now, as we have lots of procedural calls still, which we cannot really fix right now. So we would have to do the function hack for drupal_save_session, drupal_set_time_limit, watchdog, watchdog_exception, oh and the constants that are used. We could move these out into separate methods etc.. and then override in a test but this seems like a lot of effort just for eeking out a unit test and something we would have to remove again later.

We have appropriate test coverage for this, just not unit tests. We can add this at a later date (I'll add a follow up issue when this is in). How does that sound?

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

We can add this at a later date (I'll add a follow up issue when this is in). How does that sound?

+1!!

sun’s picture

+++ b/core/lib/Drupal/Core/Cron.php
@@ -0,0 +1,158 @@
+    // Force the current user to anonymous to ensure consistent permissions on
+    // cron runs.
+    // @todo This currently does not work, as it will affect the current user
+    //   being injected into services.
+    $original_user = $GLOBALS['user'];
+    $GLOBALS['user'] = new UserSession();
...
+    // Restore the user.
+    // @todo This currently does not work, as it will affect the current user
+    //   being injected into services.
+    $GLOBALS['user'] = $original_user;
+    drupal_save_session($original_session_saving);

Just inject the current_user service...?

damiankloip’s picture

StatusFileSize
new18.24 KB

Oh, there's a current_user service?! ;)

So, we inject the current_user service, then what? You can't switch users this way. So any services that use the current_user service will not be synchonrized. This is what the @todo about the current user pertains to. If it was that easy, I think we would have just done that...

Also, rerolled patch.

dawehner’s picture

When we wrote the current_user service I know that people told me that switching the current user during a request forth and back is an edge case. HAHAH

berdir’s picture

When we wrote the current_user service I know that people told me that switching the current user during a request forth and back is an edge case. HAHAH

Then you were told by the wrong people ;) I know there are use cases like this, an issue to add a function to wrap this has been open since forever. I have no clue how to be able to do this with the current_user service.

The only thing I can think of would be to stop injecting the user and inject the authentication manager and get the user from that, not offering a service for the current user (we can still have Drupal::currentUser()), then we can replace the user there and also offer something like #287292: Add functionality to impersonate a user on the authentication manager. But that would be another non-trivial API change around all this.

ParisLiakos’s picture

current_user service is synchronized, so all you need is a setCurrentUser() method in your object and it will be updated by the DIC.
we just need to make sure that every object that has current_user as a dependency has this method. Then the service would be updated everywhere, no?
Or thats not the problem?

damiankloip’s picture

Yes, we know that part :) this doesn't help us actually change the user though. As we'd only get the user object. This discussion is escalating and should definitely move to a separate issue.

ParisLiakos’s picture

I am not sure i agree

The correct thing to do imo is make Cron service ContainerAware and instead of manipulating the $user global it should do sth like:

$original_user = clone $this->currentUser;
$this->container->set('current_user', new UserSession());
......
$this->container->set('current_user', $original_user);

but a followup is fine with me, because this might open a can of worms

ParisLiakos’s picture

probably though we already have this followup created #2108623: Installing via the UI no longer logs in user 1 every time
i suspect the same with @tim.plunkett

so, lets move on here

berdir’s picture

Agreed. Already making the cron path a normal route was a win for modules like elysia_cron, as they don't have to ship their own cron.php anymore, this is even better, they can just replace the service and it then all cron executions will use their implemention. Right now, they have to do all kinds of tricks to prevent the default cron being executed.

+1 to RTBC.

alexpott’s picture

Title: Replace drupal_cron_run() with a Cron service » Change notification: Replace drupal_cron_run() with a Cron service
Priority: Normal » Major
Status: Reviewed & tested by the community » Active
Issue tags: +Needs change record

Committed 9da7e4c and pushed to 8.x. Thanks!

dawehner’s picture

current_user service is synchronized, so all you need is a setCurrentUser() method in your object and it will be updated by the DIC.

... Well this just works in cases of services, but sadly not on plugins which also uses the accounts all over the place.

ParisLiakos’s picture

ah, yes didnt think of that.
well then we need to make plugin managers do this job, or something like what Berdir suggested in #15

les lim’s picture

Status: Active » Fixed
Issue tags: -Needs change record

Posted change notice: https://drupal.org/node/2181921

jibran’s picture

Title: Change notification: Replace drupal_cron_run() with a Cron service » Replace drupal_cron_run() with a Cron service
Priority: Major » Normal

Thanks for the change notice @Les Lim.

Crell’s picture

Ooo... I only just saw this because of the change notice. I like. As a follow-up, could we refactor the run() method? It's still extremely fugly. (Switching hook_cron to an event would probably be harder to get away with at this point, but something we should still look into doing.)

berdir’s picture

@Crell: I don't think events is a good match here, I'd rather see plugins. Events would make it hard for modules like Elysia cron/Ultimate cron, that allow to configure each hook implementation differently. But I doubt that's a 8.x task :)

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.