001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.asyncTasks; 019 020import io.stallion.Context; 021import io.stallion.dataAccess.ModelBase; 022import io.stallion.dataAccess.UniqueKey; 023import io.stallion.plugins.javascript.JsAsyncTaskHandler; 024import io.stallion.services.Log; 025import io.stallion.utils.json.JSON; 026 027import javax.persistence.Column; 028import javax.persistence.Table; 029 030import static io.stallion.utils.Literals.empty; 031 032@Table(name="stallion_async_tasks") 033public class AsyncTask extends ModelBase implements Comparable<AsyncTask> { 034 private long createdAt = 0; 035 private long updatedAt = 0; 036 private String handlerName; 037 private String customKey = null; 038 private long lockedAt = 0; 039 private long failedAt = 0; 040 private long completedAt = 0; 041 private long originallyScheduledFor; 042 private long executeAt = 0; 043 private boolean neverRetry = false; 044 private String lockUuid = ""; 045 private String secret = ""; 046 private int tryCount = 0; 047 private String errorMessage = ""; 048 private String dataJson = ""; 049 private String localMode = ""; 050 051 052 public static AsyncTaskController controller() { 053 return (AsyncTaskController)Context.dal().get("st-async-async-tasks"); 054 } 055 056 public AsyncTask() { 057 058 } 059 060 public AsyncTask(AsyncTaskHandler handler) { 061 this(handler, null, 0); 062 063 } 064 065 public AsyncTask(AsyncTaskHandler handler, String customKey, long executeAt) { 066 setHandler(handler).setCustomKey(customKey).setExecuteAt(executeAt); 067 } 068 069 public AsyncTask enqueue() { 070 AsyncCoordinator.instance().enqueue(this); 071 return this; 072 } 073 074 /** 075 * When the task was created, in epoch milliseconds 076 * @return 077 */ 078 @Column 079 public long getCreatedAt() { 080 return createdAt; 081 } 082 083 public AsyncTask setCreatedAt(long createdAt) { 084 this.createdAt = createdAt; 085 return this; 086 } 087 088 /** 089 * When the task was last updated, in epoch milliseconds 090 * @return 091 */ 092 @Column 093 public long getUpdatedAt() { 094 return updatedAt; 095 } 096 097 public AsyncTask setUpdatedAt(long updatedAt) { 098 this.updatedAt = updatedAt; 099 return this; 100 } 101 102 /** 103 * The name of the handler class. When loading a task after reboot, the handler class 104 * will be looked up and loaded by using this name. 105 * 106 * @return 107 */ 108 @Column 109 public String getHandlerName() { 110 return handlerName; 111 } 112 113 /** 114 * Will use the handler class name, for later reloading, and then convert the handler to JSON 115 * and assign the data to the dataJson field of this task. 116 * @param handler 117 * @return 118 */ 119 public AsyncTask setHandler(AsyncTaskHandler handler) { 120 121 if (handler instanceof JsAsyncTaskHandler) { 122 setHandlerName(((JsAsyncTaskHandler) handler).getHandlerClassName()); 123 setDataJson(JSON.stringify(((JsAsyncTaskHandler) handler).getInternalMap())); 124 Log.info("STRIFIGYD {0}", JSON.stringify(((JsAsyncTaskHandler) handler).getInternalMap())); 125 } else { 126 setHandlerName(handler.getClass().getCanonicalName()); 127 setDataJson(JSON.stringify(handler)); 128 } 129 130 return this; 131 } 132 133 public AsyncTask setHandlerName(String handlerName) { 134 this.handlerName = handlerName; 135 return this; 136 } 137 138 /** 139 * A user generated unique key for the task, used for updating the task or preventing duplicates. 140 * @return 141 */ 142 @Column 143 @UniqueKey 144 public String getCustomKey() { 145 return customKey; 146 } 147 148 public AsyncTask setCustomKey(String customKey) { 149 this.customKey = customKey; 150 return this; 151 } 152 153 /** 154 * When the task was locked, in epoch milliseconds 155 * @return 156 */ 157 @Column 158 public long getLockedAt() { 159 return lockedAt; 160 } 161 162 public AsyncTask setLockedAt(long lockedAt) { 163 this.lockedAt = lockedAt; 164 return this; 165 } 166 167 /** 168 * When the task last failed, in epoch milliseconds 169 * @return 170 */ 171 @Column 172 public long getFailedAt() { 173 return failedAt; 174 } 175 176 public AsyncTask setFailedAt(long failedAt) { 177 this.failedAt = failedAt; 178 return this; 179 } 180 181 /** 182 * When the task successfully completed, in epoch milliseconds 183 * @return 184 */ 185 @Column 186 public long getCompletedAt() { 187 return completedAt; 188 } 189 190 public AsyncTask setCompletedAt(long completedAt) { 191 this.completedAt = completedAt; 192 return this; 193 } 194 195 /** 196 * When the task was scheduled for originally, before any failures that made the 197 * coordinator reschedule it for a retried execution. For a task that has never been 198 * run, this time will equal the executeAt time. 199 * 200 * @return 201 */ 202 @Column 203 public long getOriginallyScheduledFor() { 204 return originallyScheduledFor; 205 } 206 207 public AsyncTask setOriginallyScheduledFor(long originallyScheduledFor) { 208 this.originallyScheduledFor = originallyScheduledFor; 209 return this; 210 } 211 212 /** 213 * When the task should execute, in epoch milliseconds. 214 * 215 * @return 216 */ 217 @Column 218 public long getExecuteAt() { 219 return executeAt; 220 } 221 222 public AsyncTask setExecuteAt(long executeAt) { 223 this.executeAt = executeAt; 224 return this; 225 } 226 227 /** 228 * If true, the task should never be retried on failure. 229 * @return 230 */ 231 @Column 232 public boolean isNeverRetry() { 233 return neverRetry; 234 } 235 236 public AsyncTask setNeverRetry(boolean neverRetry) { 237 this.neverRetry = neverRetry; 238 return this; 239 } 240 241 /** 242 * A unique lock key, generated by the async persister when locking a task. 243 * @return 244 */ 245 @Column 246 public String getLockUuid() { 247 return lockUuid; 248 } 249 250 public AsyncTask setLockUuid(String lockUuid) { 251 this.lockUuid = lockUuid; 252 return this; 253 } 254 255 /** 256 * A secret key, generated by the async persister, that can be used for 257 * looking up the task object. 258 * @return 259 */ 260 @Column 261 @UniqueKey 262 public String getSecret() { 263 return secret; 264 } 265 266 public AsyncTask setSecret(String secret) { 267 this.secret = secret; 268 return this; 269 } 270 271 /** 272 * How many times the task has been tried to execute, incremented every time the task fails. 273 * 274 * @return 275 */ 276 @Column 277 public int getTryCount() { 278 return tryCount; 279 } 280 281 public AsyncTask setTryCount(int tryCount) { 282 this.tryCount = tryCount; 283 return this; 284 } 285 286 /** 287 * The stack trace from the last failure. 288 * @return 289 */ 290 @Column 291 public String getErrorMessage() { 292 return errorMessage; 293 } 294 295 public AsyncTask setErrorMessage(String errorMessage) { 296 this.errorMessage = errorMessage; 297 return this; 298 } 299 300 /** 301 * The async handler instance will be serialized to this field during task creation. When the task 302 * is executed, the this field will be deserialized and used to hydrate the fields of the 303 * handler class. 304 * @return 305 */ 306 @Column 307 public String getDataJson() { 308 return dataJson; 309 } 310 311 public AsyncTask setDataJson(String data) { 312 this.dataJson = data; 313 return this; 314 } 315 316 /** 317 * Parses getDataJson() and returns the resulting class. 318 * 319 * @param cls 320 * @param <V> 321 * @return 322 */ 323 public <V> V getData(Class<? extends V> cls) { 324 if (!empty(this.dataJson )) { 325 return JSON.parse(this.dataJson, cls); 326 } else { 327 return null; 328 } 329 } 330 331 /** 332 * JSON Stringifys the object and sets this.dataJson 333 * 334 * @param o 335 */ 336 public void setData(Object o) { 337 this.dataJson = JSON.stringify(o); 338 } 339 340 /** 341 * Implements the comparable interface to see which task should be executed sooner. 342 * 343 * @param o 344 * @return 345 */ 346 @Override 347 public int compareTo(AsyncTask o) { 348 return Long.compare(this.getExecuteAt(), o.getExecuteAt()); 349 } 350 351 public String getLocalMode() { 352 return localMode; 353 } 354 355 public AsyncTask setLocalMode(String localMode) { 356 this.localMode = localMode; 357 return this; 358 } 359}