Class: Parse::JobStatus

Inherits:
Object show all
Defined in:
lib/parse/model/classes/job_status.rb

Overview

Note:

This collection is written by Parse Server itself and read access typically requires the master key. Parse Server does not garbage-collect ‘_JobStatus` rows — long-running deployments accumulate history and should implement their own retention policy.

This class represents the data and columns contained in the standard Parse ‘_JobStatus` collection. Parse Server writes a row here every time a background job (registered via Parse.Cloud.job(…)) runs, recording its outcome and any status/message updates emitted via response.message(…).

The default schema for JobStatus is as follows:

class Parse::JobStatus < Parse::Object
   # See Parse::Object for inherited properties...

   property :job_name
   property :source             # how the job was invoked
   property :status             # "running", "succeeded", "failed"
   property :message            # latest status message emitted by the job
   property :params, :object    # parameters the job was invoked with
   property :finished_at, :date # when the job stopped running
end

*Defining a job*

Jobs are registered in your Parse Server’s Cloud Code (server-side JavaScript), not in this Ruby SDK. A minimal example:

// cloud/main.js
Parse.Cloud.job("nightlyCleanup", async (request) => {
  const { params, headers, log, message } = request;
  message("Starting cleanup...");
  const query = new Parse.Query("_Session");
  query.lessThan("expiresAt", new Date());
  const sessions = await query.find({ useMasterKey: true });
  await Parse.Object.destroyAll(sessions, { useMasterKey: true });
  message(`Deleted ${sessions.length} sessions`);
  return `ok`;
});

*Invoking a job*

Once registered, a job can be triggered ad-hoc via REST (requires the master key):

POST /parse/jobs/nightlyCleanup
X-Parse-Application-Id: ...
X-Parse-Master-Key: ...
Content-Type: application/json

{ "someParam": "value" }

The request returns immediately with a ‘_JobStatus` `objectId`; the job itself runs asynchronously, and the `_JobStatus` row is updated as it progresses. For recurring runs, configure a JobSchedule row via the Parse Dashboard’s “Jobs” tab — Parse Server’s scheduler will invoke the job at the configured times.

*Reading job status from Ruby*

# Has the nightly cleanup run today?
latest = Parse::JobStatus.latest_for("nightlyCleanup")
puts "Last run: #{latest.status} at #{latest.created_at}"
puts "Duration: #{latest.duration}s" if latest.finished?

# Find failed jobs in the last 24h
yesterday = Time.now - 86_400
Parse::JobStatus.failed.where(:created_at.gt => yesterday).all

Constant Summary collapse

STATUS_RUNNING =

Parse Server’s terminal status values, written by ‘setFinalStatus` in `StatusHandler.js`. Mirrored here so callers can compare against named constants instead of hard-coding strings.

"running"
STATUS_SUCCEEDED =
"succeeded"
STATUS_FAILED =
"failed"

Constants inherited from Object

Object::BUILTIN_PARSE_CLASS_NAMES, Object::IDENTIFICATION_FIELDS, Object::VALID_ACL_POLICIES

Constants included from Core::Schema

Core::Schema::DEFAULT_PUBLIC_CLP, Core::Schema::SCHEMA_READONLY_CLASSES

Constants included from Core::Describe

Core::Describe::ALL_SECTIONS, Core::Describe::CORE_FIELD_KEYS, Core::Describe::LOCAL_SECTIONS, Core::Describe::NETWORK_SECTIONS

Constants included from Core::Indexing

Core::Indexing::MAX_INDEXES_PER_COLLECTION, Core::Indexing::PARSE_MANAGED_ARRAY_FIELDS, Core::Indexing::SENSITIVE_FIELDS

Constants included from Core::SearchIndexing

Core::SearchIndexing::ALLOWED_INDEX_TYPES, Core::SearchIndexing::INDEX_NAME_PATTERN

Constants included from Core::Fetching

Core::Fetching::NON_SERIALIZABLE_IVARS

Constants included from Core::ParseReference

Core::ParseReference::OBJECT_ID_LENGTH, Core::ParseReference::SEPARATOR

Constants included from Core::FieldGuards

Core::FieldGuards::GUARD_MODES

Constants included from Properties

Properties::BASE, Properties::BASE_FIELD_MAP, Properties::BASE_KEYS, Properties::CORE_FIELDS, Properties::DELETE_OP, Properties::PROTECTED_INITIALIZE_KEYS, Properties::PROTECTED_MASS_ASSIGNMENT_KEYS, Properties::TYPES

Constants inherited from Pointer

Pointer::ATTRIBUTES, Pointer::OBJECT_ID_FORMAT

Constants inherited from Model

Model::CLASS_AUDIENCE, Model::CLASS_INSTALLATION, Model::CLASS_JOB_SCHEDULE, Model::CLASS_JOB_STATUS, Model::CLASS_PRODUCT, Model::CLASS_PUSH_STATUS, Model::CLASS_ROLE, Model::CLASS_SCHEMA, Model::CLASS_SESSION, Model::CLASS_USER, Model::ID, Model::KEY_CLASS_NAME, Model::KEY_CREATED_AT, Model::KEY_OBJECT_ID, Model::KEY_UPDATED_AT, Model::OBJECT_ID, Model::TYPE_ACL, Model::TYPE_BYTES, Model::TYPE_DATE, Model::TYPE_FIELD, Model::TYPE_FILE, Model::TYPE_GEOPOINT, Model::TYPE_NUMBER, Model::TYPE_OBJECT, Model::TYPE_POINTER, Model::TYPE_POLYGON, Model::TYPE_RELATION

Instance Attribute Summary collapse

Attributes inherited from Object

#acl, #created_at, #id, #updated_at

Attributes inherited from Pointer

#id, #parse_class

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Object

#[], #[]=, #__type, #_resolve_acl_owner_id, #_resolve_default_acl, #acl_changed?, acl_owner_field, acl_policy, acl_policy_setting, #acl_was, #acl_will_change!, #after_create, #after_destroy, #after_save, #after_update, #after_validation, #apply_defaults!, #around_create, #around_destroy, #around_save, #around_update, #around_validation, #as_json, #autofetch_disabled?, #before_create, #before_destroy, #before_save, #before_update, #before_validation, build, #changed, #changed?, class_permissions, #clear_attribute_change!, #clear_changes!, #clear_partial_fetch_state!, default_acls, describe_access, #disable_autofetch!, #enable_autofetch!, #existed?, fetch_clp, #fetched?, #fetched_keys, #fetched_keys=, #field_was_fetched?, #filter_for_user, filter_results_for_user, #fully_fetched?, #has?, #has_selective_keys?, #initialize, #keys, master_only_class!, #nested_fetched_keys, #nested_fetched_keys=, #nested_keys_for, #new?, #parse_class, #partially_fetched?, #persisted?, pointer, #pretty, private_acl!, protect_fields, #reload!, roles_for_user, #rollback!, #run_after_create_callbacks, #run_after_delete_callbacks, #run_after_save_callbacks, #schema, set_class_access, set_clp, set_default_acl, set_default_clp, set_read_user_fields, set_write_user_fields, #twin, unlistable_class!, update_clp!, #updates, #valid?, #validate!, webhook, webhook_function

Methods included from Core::Querying

#all, #count, #count_distinct, #cursor, #distinct, #each, #find, #find_cached, #first, #last_updated, #latest, #literal_where, #newest, #oldest, #query, #scope, #subscribe

Methods included from Core::Schema

#_default_class_level_permissions_for_upgrade, #auto_upgrade!, #create_schema, #fetch_schema, #reset_clp!, #schema, #update_schema

Methods included from Core::Describe

#describe

Methods included from Core::Indexing

#apply_indexes!, #indexes_plan, #mongo_geo_index, #mongo_index, #mongo_index_declarations, #mongo_relation_index

Methods included from Core::SearchIndexing

#apply_search_indexes!, #mongo_search_index, #mongo_search_index_declarations, #search_indexes_plan

Methods included from Agent::MetadataDSL

#agent_description, #agent_methods, included, #property_descriptions, #property_enum_descriptions

Methods included from Core::Actions

#_deleted?, #change_requests, #changes_applied!, #changes_payload, #create, #destroy, #destroy_request, #op_add!, #op_add_relation!, #op_add_unique!, #op_destroy!, #op_increment!, #op_remove!, #op_remove_relation!, #operate_field!, #prepare_save!, #relation_change_operations, #save, #save!, #set_attributes!, #update, #update!, #update_relations, #uri_path

Methods included from Core::Fetching

#autofetch!, #fetch, #fetch!, #fetch_cache!, #fetch_json, #fetch_object, #prepare_for_dirty_tracking!

Methods included from Associations::HasMany

has_many, #relation_changes?, #relation_updates, #relations

Methods included from Associations::BelongsTo

belongs_to, #key?

Methods included from Associations::HasOne

has_one

Methods included from Core::ParseReference

format, generate_object_id, parse

Methods included from Core::FieldGuards

#apply_field_guards!

Methods included from Core::EnhancedChangeTracking

included

Methods included from Properties

#apply_attributes!, #attribute_changes?, #attribute_updates, #attributes, #attributes=, #field_map, #fields, #format_operation, #format_value

Methods inherited from Pointer

#==, #[], #[]=, #__type, #attributes, #className, #fetch, #fetch_cache!, #fetch_json, #fetch_object, #fetched?, #hash, #initialize, #json_hash, #method_missing, #pointer, #pointer?, #present?, #respond_to_missing?, #sig

Methods inherited from Model

#dirty?, find_class

Methods included from Client::Connectable

#client

Constructor Details

This class inherits a constructor from Parse::Object

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Parse::Pointer

Instance Attribute Details

#finished_atParse::Date

Timestamp when the job stopped running. Nil while the job is still in-flight.

Returns:



127
# File 'lib/parse/model/classes/job_status.rb', line 127

property :finished_at, :date

#job_nameString

The name the job was registered under (the first argument to Parse.Cloud.job).

Returns:



96
# File 'lib/parse/model/classes/job_status.rb', line 96

property :job_name

#messageString

The most recent status message emitted by the job via response.message(…).

Returns:



116
# File 'lib/parse/model/classes/job_status.rb', line 116

property :message

#paramsHash

The parameters the job was invoked with.

Returns:



121
# File 'lib/parse/model/classes/job_status.rb', line 121

property :params, :object

#sourceString

How the job was invoked. Parse Server itself hard-codes “api” in StatusHandler.js for runs triggered via POST /parse/jobs/<name>; external schedulers (parse-server-scheduler, dashboard cron tooling) may inject other values when they create the _JobStatus row.

Returns:



104
# File 'lib/parse/model/classes/job_status.rb', line 104

property :source

#statusString

Current state of the job run. Common values are “running”, “succeeded”, and “failed”.

Returns:



110
# File 'lib/parse/model/classes/job_status.rb', line 110

property :status

Class Method Details

.cleanup_older_than!(days: 30, terminal_only: true) ⇒ Integer

Delete ‘_JobStatus` rows older than the given threshold. Parse Server does not garbage-collect this collection on its own, so long-running deployments accumulate run history indefinitely. Mirrors Installation.cleanup_stale_tokens!.

By default (‘terminal_only: true`), only rows in a terminal state (`succeeded` or `failed`) are eligible — an orphaned `status == “running”` row from a crashed worker is preserved, as is any row with an external-scheduler-injected status the SDK doesn’t recognize. Set ‘terminal_only: false` to drop the status guard and reap every row older than the cutoff regardless of state (use with care for orphan cleanup).

Use with caution — permanently removes job-history records.

Examples:

deleted = Parse::JobStatus.cleanup_older_than!(days: 90)

Parameters:

  • days (Integer) (defaults to: 30)

    number of days since ‘created_at` (default: 30). Negative values are accepted and produce a future cutoff (useful in tests for “delete everything older than now-plus-a-minute”).

  • terminal_only (Boolean) (defaults to: true)

    when true (default), restrict the destroy to rows whose status is ‘succeeded` or `failed`. When false, every row older than the cutoff is eligible.

Returns:

  • (Integer)

    the number of rows deleted



222
223
224
225
226
227
228
229
230
# File 'lib/parse/model/classes/job_status.rb', line 222

def cleanup_older_than!(days: 30, terminal_only: true)
  scope = older_than(days: days)
  if terminal_only
    scope = scope.where(:status.in => [STATUS_SUCCEEDED, STATUS_FAILED])
  end
  stale = scope.all
  stale.each(&:destroy)
  stale.count
end

.failedParse::Query

Query for jobs that failed.

Returns:



151
152
153
# File 'lib/parse/model/classes/job_status.rb', line 151

def failed
  query(status: STATUS_FAILED)
end

.for_job(name) ⇒ Parse::Query

Query scope for runs of a specific job by name.

Parameters:

Returns:



165
166
167
# File 'lib/parse/model/classes/job_status.rb', line 165

def for_job(name)
  query(job_name: name.to_s)
end

.latest_for(name) ⇒ Parse::JobStatus?

The most recently started run of the named job (any status), ordered by ‘created_at`. Useful for “did the nightly cleanup run yet?” introspection. Note that for a still-running job this may return the in-flight row even after subsequent attempts have finished — `created_at` is the start time, not the finish time.

Parameters:

Returns:



176
177
178
# File 'lib/parse/model/classes/job_status.rb', line 176

def latest_for(name)
  for_job(name).order(:created_at.desc).first
end

.older_than(days: 30) ⇒ Parse::Query

Query scope for ‘_JobStatus` rows older than the given threshold.

Examples:

stale = Parse::JobStatus.older_than(days: 90).all

Parameters:

  • days (Integer) (defaults to: 30)

    number of days since the row’s ‘created_at` (default: 30)

Returns:



186
187
188
189
# File 'lib/parse/model/classes/job_status.rb', line 186

def older_than(days: 30)
  cutoff = Time.now - (days * 24 * 60 * 60)
  query(:created_at.lt => cutoff)
end

.older_than_count(days: 30) ⇒ Integer

Count ‘_JobStatus` rows older than the given threshold.

Parameters:

  • days (Integer) (defaults to: 30)

    number of days since ‘created_at` (default: 30)

Returns:

  • (Integer)


194
195
196
# File 'lib/parse/model/classes/job_status.rb', line 194

def older_than_count(days: 30)
  older_than(days: days).count
end

.recent(limit: 100) ⇒ Parse::Query

Query for the most recent job status rows, newest first.

Parameters:

  • limit (Integer) (defaults to: 100)

    number of rows to return (default: 100)

Returns:



158
159
160
# File 'lib/parse/model/classes/job_status.rb', line 158

def recent(limit: 100)
  query.order(:created_at.desc).limit(limit)
end

.runningParse::Query

Query for jobs currently in the running state.

Returns:



139
140
141
# File 'lib/parse/model/classes/job_status.rb', line 139

def running
  query(status: STATUS_RUNNING)
end

.succeededParse::Query

Query for jobs that completed successfully.

Returns:



145
146
147
# File 'lib/parse/model/classes/job_status.rb', line 145

def succeeded
  query(status: STATUS_SUCCEEDED)
end

Instance Method Details

#durationFloat?

Wall-clock duration of the run as a ‘Float` number of seconds, or `nil` while the job is still in-flight (or if either timestamp is missing).

Returns:

  • (Float, nil)


259
260
261
262
# File 'lib/parse/model/classes/job_status.rb', line 259

def duration
  return nil if finished_at.nil? || created_at.nil?
  finished_at.to_time - created_at.to_time
end

#failed?Boolean

Returns true if this run failed.

Returns:

  • (Boolean)

    true if this run failed.



244
245
246
# File 'lib/parse/model/classes/job_status.rb', line 244

def failed?
  status == STATUS_FAILED
end

#finished?Boolean

Returns true if the run has reached a terminal state (succeeded or failed). Parse Server writes ‘finished_at` at the same time it transitions out of `running`, so either signal is acceptable; we check `finished_at` first because it’s the more authoritative one.

Returns:

  • (Boolean)

    true if the run has reached a terminal state (succeeded or failed). Parse Server writes ‘finished_at` at the same time it transitions out of `running`, so either signal is acceptable; we check `finished_at` first because it’s the more authoritative one.



252
253
254
# File 'lib/parse/model/classes/job_status.rb', line 252

def finished?
  !finished_at.nil? || succeeded? || failed?
end

#running?Boolean

Returns true if this row is in the running state.

Returns:

  • (Boolean)

    true if this row is in the running state.



234
235
236
# File 'lib/parse/model/classes/job_status.rb', line 234

def running?
  status == STATUS_RUNNING
end

#succeeded?Boolean

Returns true if this run completed successfully.

Returns:

  • (Boolean)

    true if this run completed successfully.



239
240
241
# File 'lib/parse/model/classes/job_status.rb', line 239

def succeeded?
  status == STATUS_SUCCEEDED
end