Skip to content

Cron and queue

Membership expiration is handled in two steps: hook_cron finds memberships that need to be expired and enqueues them; a queue worker processes each item by calling the membership’s term plugin’s expire() method.

hook_cron

Implementation: Drupal\crm_membership\Hook\CoreHooks::cron()
File: src/Hook/CoreHooks.php

On each cron run, the hook:

  1. Memberships with no current periods — Finds all memberships with status not expired and current_periods empty. These are treated as needing expiration (e.g. they were active but something left them without a valid period).
  2. Memberships with only expired periods — Finds memberships that are not yet marked expired but whose referenced current_periods all have date_range.end_value in the past. So if at least one period is still active, the membership is skipped; if every current period has ended, it is queued.
  3. Enqueue — For each membership ID from (1) and (2), creates one item on the queue crm_membership_expiration with payload ['crm_membership_id' => $membership_id].

The hook does not change any membership or period itself; it only adds items to the queue. Date comparison uses the storage timezone and datetime format from DateTimeItemInterface.

Queue worker

Queue ID: crm_membership_expiration
Class: Drupal\crm_membership\Plugin\QueueWorker\MembershipExpiration
File: src/Plugin/QueueWorker/MembershipExpiration.php
Cron time: 60 seconds (so cron will process this queue for up to 60 seconds per run).

For each queue item:

  1. Reads crm_membership_id from the item data.
  2. Loads the crm_membership entity.
  3. Gets the membership’s Membership Term plugin via $membership->getMembershipTerm().
  4. Calls $membershipTerm->expire().

The term plugin’s expire() is responsible for updating the membership (e.g. set status to expired, remove or adjust current_periods, and save). The queue worker does not perform any other logic.

Summary

Step Component Action
1 CoreHooks::cron() Find memberships without current periods or with only expired periods; enqueue each by ID.
2 MembershipExpiration::processItem() Load membership, get term plugin, call expire().

Ensure cron is running (e.g. via system cron or Drupal’s cron) so that expirations are processed regularly. The 60-second cron time limit means only a subset of queued items may be processed per run if there are many expirations.