@hotmeshio/hotmesh 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,13 @@ async function sleepFor(ms) {
6
6
  }
7
7
  exports.sleepFor = sleepFor;
8
8
  function identifyRedisType(redisInstance) {
9
+ const prototype = Object.getPrototypeOf(redisInstance);
10
+ if ('defineCommand' in prototype || Object.keys(prototype).includes('multi')) {
11
+ return 'ioredis';
12
+ }
13
+ else if (Object.keys(prototype).includes('Multi')) {
14
+ return 'redis';
15
+ }
9
16
  if (redisInstance.constructor) {
10
17
  if (redisInstance.constructor.name === 'Redis' || redisInstance.constructor.name === 'EventEmitter') {
11
18
  if ('hset' in redisInstance) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -1,9 +1,9 @@
1
+ import { Activity } from './activity';
1
2
  import { EngineService } from '../engine';
2
3
  import { ActivityData, ActivityMetadata, ActivityType, HookActivity } from '../../types/activity';
4
+ import { HookRule } from '../../types/hook';
3
5
  import { JobState, JobStatus } from '../../types/job';
4
6
  import { RedisMulti } from '../../types/redis';
5
- import { HookRule } from '../../types/hook';
6
- import { Activity } from './activity';
7
7
  /**
8
8
  * Listens for `webhook`, `timehook`, and `cycle` (repeat) signals
9
9
  */
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Hook = void 0;
4
4
  const errors_1 = require("../../modules/errors");
5
+ const activity_1 = require("./activity");
5
6
  const collator_1 = require("../collator");
6
7
  const pipe_1 = require("../pipe");
7
8
  const store_1 = require("../signaler/store");
8
9
  const telemetry_1 = require("../telemetry");
9
- const activity_1 = require("./activity");
10
- const types_1 = require("../../types");
10
+ const stream_1 = require("../../types/stream");
11
11
  /**
12
12
  * Listens for `webhook`, `timehook`, and `cycle` (repeat) signals
13
13
  */
@@ -107,7 +107,7 @@ class Hook extends activity_1.Activity {
107
107
  if (jobId) {
108
108
  //if a webhook signal is sent that includes 'keep_alive' the hook will remain open
109
109
  const code = data.keep_alive ? 202 : 200;
110
- await this.processEvent(types_1.StreamStatus.SUCCESS, code, 'hook', jobId);
110
+ await this.processEvent(stream_1.StreamStatus.SUCCESS, code, 'hook', jobId);
111
111
  if (code === 200) {
112
112
  await signaler.deleteWebHookSignal(this.config.hook.topic, data);
113
113
  }
@@ -118,7 +118,7 @@ class Hook extends activity_1.Activity {
118
118
  jid: jobId,
119
119
  aid: this.metadata.aid
120
120
  });
121
- await this.processEvent(types_1.StreamStatus.SUCCESS, 200, 'hook');
121
+ await this.processEvent(stream_1.StreamStatus.SUCCESS, 200, 'hook');
122
122
  }
123
123
  }
124
124
  exports.Hook = Hook;
@@ -6,46 +6,7 @@ const factory_1 = require("./factory");
6
6
  const handle_1 = require("./handle");
7
7
  const hotmesh_1 = require("../hotmesh");
8
8
  const key_1 = require("../../modules/key");
9
- /*
10
- Here is an example of how the methods in this file are used:
11
-
12
- ./client.ts
13
-
14
- import { Durable } from '@hotmeshio/hotmesh';
15
- import Redis from 'ioredis';
16
- import { example } from './workflows';
17
- import { nanoid } from 'nanoid';
18
-
19
- async function run() {
20
- const connection = await Durable.Connection.connect({
21
- class: Redis,
22
- options: {
23
- host: 'localhost',
24
- port: 6379,
25
- },
26
- });
27
-
28
- const client = new Durable.Client({
29
- connection,
30
- });
31
-
32
- const handle = await client.workflow.start({
33
- args: ['HotMesh'],
34
- taskQueue: 'hello-world',
35
- workflowName: 'example',
36
- workflowId: 'workflow-' + nanoid(),
37
- });
38
-
39
- console.log(`Started workflow ${handle.workflowId}`);
40
- console.log(await handle.result());
41
- }
42
-
43
- run().catch((err) => {
44
- console.error(err);
45
- process.exit(1);
46
- });
47
-
48
- */
9
+ const search_1 = require("./search");
49
10
  class ClientService {
50
11
  constructor(config) {
51
12
  this.getHotMeshClient = async (worflowTopic) => {
@@ -81,7 +42,7 @@ class ClientService {
81
42
  * this method will configure the search index for the workflow.
82
43
  */
83
44
  this.configureSearchIndex = async (hotMeshClient, search) => {
84
- if (search) {
45
+ if (search?.schema) {
85
46
  const store = hotMeshClient.engine.store;
86
47
  const schema = [];
87
48
  for (const [key, value] of Object.entries(search.schema)) {
@@ -129,6 +90,13 @@ class ClientService {
129
90
  };
130
91
  const context = { metadata: { trc, spn }, data: {} };
131
92
  const jobId = await hotMeshClient.pub(factory_1.SUBSCRIBES_TOPIC, payload, context);
93
+ if (jobId && options.search?.data) {
94
+ //job successfully kicked off; there is default job data to persist
95
+ const search = new search_1.Search(jobId, hotMeshClient);
96
+ for (const [key, value] of Object.entries(options.search.data)) {
97
+ search.set(key, value);
98
+ }
99
+ }
132
100
  return new handle_1.WorkflowHandleService(hotMeshClient, workflowTopic, jobId);
133
101
  },
134
102
  signal: async (signalId, data) => {
@@ -1,5 +1,5 @@
1
1
  import { HotMeshService as HotMesh } from '../hotmesh';
2
- import { Connection, Registry, WorkerConfig, WorkerOptions } from "../../types/durable";
2
+ import { Connection, Registry, WorkerConfig, WorkerOptions, WorkflowSearchOptions } from "../../types/durable";
3
3
  export declare class WorkerService {
4
4
  static activityRegistry: Registry;
5
5
  static connection: Connection;
@@ -14,6 +14,11 @@ export declare class WorkerService {
14
14
  * allowing proxyActivities to succeed.
15
15
  */
16
16
  static registerActivities<ACT>(activities: ACT): Registry;
17
+ /**
18
+ * For those deployments with a redis stack backend (with the FT module),
19
+ * this method will configure the search index for the workflow.
20
+ */
21
+ static configureSearchIndex(hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void>;
17
22
  static create(config: WorkerConfig): Promise<WorkerService>;
18
23
  static resolveWorkflowTarget(workflow: object | Function): [string, Function];
19
24
  run(): Promise<void>;
@@ -7,36 +7,7 @@ const asyncLocalStorage_1 = require("./asyncLocalStorage");
7
7
  const factory_1 = require("./factory");
8
8
  const hotmesh_1 = require("../hotmesh");
9
9
  const stream_1 = require("../../types/stream");
10
- /*
11
- Here is an example of how the methods in this file are used:
12
-
13
- ./worker.ts
14
-
15
- import { Durable } from '@hotmeshio/hotmesh';
16
- import Redis from 'ioredis'; //OR `import * as Redis from 'redis';`
17
-
18
- import * as workflows from './workflows';
19
-
20
- async function run() {
21
- const worker = await Durable.Worker.create({
22
- connection: {
23
- class: Redis,
24
- options: {
25
- host: 'localhost',
26
- port: 6379,
27
- },
28
- },
29
- taskQueue: 'hello-world',
30
- workflow: workflows.example,
31
- });
32
- await worker.run();
33
- }
34
-
35
- run().catch((err) => {
36
- console.error(err);
37
- process.exit(1);
38
- });
39
- */
10
+ const key_1 = require("../../modules/key");
40
11
  class WorkerService {
41
12
  static async activateWorkflow(hotMesh) {
42
13
  const app = await hotMesh.engine.store.getApp(factory_1.APP_ID);
@@ -79,6 +50,38 @@ class WorkerService {
79
50
  }
80
51
  return WorkerService.activityRegistry;
81
52
  }
53
+ /**
54
+ * For those deployments with a redis stack backend (with the FT module),
55
+ * this method will configure the search index for the workflow.
56
+ */
57
+ //todo: bind this to the Search service; update constructor to expect hotMeshClient as first param (id is optional
58
+ //refactor and delete other one as well)
59
+ static async configureSearchIndex(hotMeshClient, search) {
60
+ if (search?.schema) {
61
+ const store = hotMeshClient.engine.store;
62
+ const schema = [];
63
+ for (const [key, value] of Object.entries(search.schema)) {
64
+ //prefix with a comma (avoids collisions with hotmesh reserved words)
65
+ schema.push(`_${key}`);
66
+ schema.push(value.type);
67
+ if (value.sortable) {
68
+ schema.push('SORTABLE');
69
+ }
70
+ }
71
+ try {
72
+ const keyParams = {
73
+ appId: hotMeshClient.appId,
74
+ jobId: ''
75
+ };
76
+ const hotMeshPrefix = key_1.KeyService.mintKey(hotMeshClient.namespace, key_1.KeyType.JOB_STATE, keyParams);
77
+ const prefixes = search.prefix.map((prefix) => `${hotMeshPrefix}${prefix}`);
78
+ await store.exec('FT.CREATE', `${search.index}`, 'ON', 'HASH', 'PREFIX', prefixes.length, ...prefixes, 'SCHEMA', ...schema);
79
+ }
80
+ catch (err) {
81
+ hotMeshClient.engine.logger.info('durable-client-search-err', { err });
82
+ }
83
+ }
84
+ }
82
85
  static async create(config) {
83
86
  //always call `registerActivities` before `import`
84
87
  WorkerService.connection = config.connection;
@@ -91,6 +94,7 @@ class WorkerService {
91
94
  const worker = new WorkerService();
92
95
  worker.activityRunner = await worker.initActivityWorker(config, activityTopic);
93
96
  worker.workflowRunner = await worker.initWorkflowWorker(config, workflowTopic, workflowFunction);
97
+ WorkerService.configureSearchIndex(worker.workflowRunner, config.search);
94
98
  await WorkerService.activateWorkflow(worker.workflowRunner);
95
99
  return worker;
96
100
  }
@@ -1,11 +1,12 @@
1
1
  import { ActivityConfig, ProxyType, WorkflowOptions } from "../../types/durable";
2
+ import { Search } from './search';
2
3
  export declare class WorkflowService {
3
4
  /**
4
5
  * Spawn a child workflow. await the result.
5
6
  */
6
7
  static executeChild<T>(options: WorkflowOptions): Promise<T>;
7
8
  static proxyActivities<ACT>(options?: ActivityConfig): ProxyType<ACT>;
8
- static data(command: 'del' | 'get' | 'set' | 'incr' | 'mult', ...args: string[]): Promise<number | boolean | string>;
9
+ static search(): Promise<Search>;
9
10
  static sleep(duration: string): Promise<number>;
10
11
  static waitForSignal(signals: string[], options?: Record<string, string>): Promise<Record<any, any>[]>;
11
12
  static wrapActivity<T>(activityName: string, options?: ActivityConfig): T;
@@ -12,34 +12,6 @@ const connection_1 = require("./connection");
12
12
  const factory_1 = require("./factory");
13
13
  const errors_1 = require("../../modules/errors");
14
14
  const search_1 = require("./search");
15
- /*
16
- `proxyActivities` returns a wrapped instance of the
17
- target activity, so that when the workflow calls a
18
- proxied activity, it is actually calling the proxy
19
- function, which in turn calls the activity function.
20
-
21
- Here is an example of how the methods in this file are used:
22
-
23
- ./workflows.ts
24
-
25
- import { Durable } from '@hotmeshio/hotmesh';
26
- import * as activities from './activities';
27
-
28
- const { greet } = Durable.workflow.proxyActivities<typeof activities>({
29
- activities: activities,
30
- startToCloseTimeout: '1 minute',
31
- retryPolicy: {
32
- initialInterval: '5 seconds', // Initial delay between retries
33
- maximumAttempts: 3, // Max number of retry attempts
34
- backoffCoefficient: 2.0, // Backoff factor for delay between retries: delay = initialInterval * (backoffCoefficient ^ retry_attempt)
35
- maximumInterval: '30 seconds', // Max delay between retries
36
- },
37
- });
38
-
39
- export async function example(name: string): Promise<string> {
40
- return await greet(name);
41
- }
42
- */
43
15
  class WorkflowService {
44
16
  /**
45
17
  * Spawn a child workflow. await the result.
@@ -89,38 +61,15 @@ class WorkflowService {
89
61
  }
90
62
  return proxy;
91
63
  }
92
- static async data(command, ...args) {
64
+ static async search() {
93
65
  const store = asyncLocalStorage_1.asyncLocalStorage.getStore();
94
66
  if (!store) {
95
67
  throw new Error('durable-store-not-found');
96
68
  }
97
69
  const workflowId = store.get('workflowId');
98
70
  const workflowTopic = store.get('workflowTopic');
99
- try {
100
- const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic);
101
- const search = new search_1.Search(workflowId, hotMeshClient);
102
- if (command === 'get') {
103
- return await search.get(args[0]);
104
- }
105
- else if (command === 'set') {
106
- await search.set(args[0], args[1]);
107
- return true;
108
- }
109
- else if (command === 'del') {
110
- await search.del(args[0]);
111
- return true;
112
- }
113
- else if (command === 'incr') {
114
- return await search.incr(args[0], Number(args[1]));
115
- }
116
- else if (command === 'mult') {
117
- return await search.mult(args[0], Number(args[1]));
118
- }
119
- }
120
- catch (e) {
121
- console.error(e);
122
- return '';
123
- }
71
+ const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic);
72
+ return new search_1.Search(workflowId, hotMeshClient);
124
73
  }
125
74
  static async sleep(duration) {
126
75
  const seconds = (0, ms_1.default)(duration) / 1000;
@@ -6,12 +6,13 @@ type WorkflowConfig = {
6
6
  initialInterval?: string;
7
7
  };
8
8
  type WorkflowSearchOptions = {
9
- index: string;
10
- prefix: string[];
11
- schema: Record<string, {
9
+ index?: string;
10
+ prefix?: string[];
11
+ schema?: Record<string, {
12
12
  type: 'TEXT' | 'NUMERIC' | 'TAG';
13
13
  sortable: boolean;
14
14
  }>;
15
+ data?: Record<string, string>;
15
16
  };
16
17
  type WorkflowOptions = {
17
18
  taskQueue: string;
@@ -59,6 +60,7 @@ type WorkerConfig = {
59
60
  taskQueue: string;
60
61
  workflow: Function;
61
62
  options?: WorkerOptions;
63
+ search?: WorkflowSearchOptions;
62
64
  };
63
65
  type WorkerOptions = {
64
66
  maxSystemRetries?: number;
package/modules/utils.ts CHANGED
@@ -9,6 +9,12 @@ export async function sleepFor(ms: number) {
9
9
  }
10
10
 
11
11
  export function identifyRedisType(redisInstance: any): 'redis' | 'ioredis' | null {
12
+ const prototype = Object.getPrototypeOf(redisInstance);
13
+ if ('defineCommand' in prototype || Object.keys(prototype).includes('multi')) {
14
+ return 'ioredis';
15
+ } else if (Object.keys(prototype).includes('Multi')) {
16
+ return 'redis';
17
+ }
12
18
  if (redisInstance.constructor) {
13
19
  if (redisInstance.constructor.name === 'Redis' || redisInstance.constructor.name === 'EventEmitter') {
14
20
  if ('hset' in redisInstance) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -1,4 +1,5 @@
1
- import { CollationError, GetStateError } from '../../modules/errors';
1
+ import { GetStateError } from '../../modules/errors';
2
+ import { Activity } from './activity';
2
3
  import { CollatorService } from '../collator';
3
4
  import { EngineService } from '../engine';
4
5
  import { Pipe } from '../pipe';
@@ -8,15 +9,14 @@ import {
8
9
  ActivityData,
9
10
  ActivityMetadata,
10
11
  ActivityType,
11
- HookActivity} from '../../types/activity';
12
+ HookActivity } from '../../types/activity';
13
+ import { HookRule } from '../../types/hook';
12
14
  import { JobState, JobStatus } from '../../types/job';
13
15
  import {
14
16
  MultiResponseFlags,
15
17
  RedisMulti } from '../../types/redis';
16
18
  import { StringScalarType } from '../../types/serializer';
17
- import { HookRule } from '../../types/hook';
18
- import { Activity } from './activity';
19
- import { StreamStatus } from '../../types';
19
+ import { StreamStatus } from '../../types/stream';
20
20
 
21
21
  /**
22
22
  * Listens for `webhook`, `timehook`, and `cycle` (repeat) signals
@@ -9,47 +9,7 @@ import {
9
9
  WorkflowSearchOptions} from '../../types/durable';
10
10
  import { JobState } from '../../types/job';
11
11
  import { KeyService, KeyType } from '../../modules/key';
12
-
13
- /*
14
- Here is an example of how the methods in this file are used:
15
-
16
- ./client.ts
17
-
18
- import { Durable } from '@hotmeshio/hotmesh';
19
- import Redis from 'ioredis';
20
- import { example } from './workflows';
21
- import { nanoid } from 'nanoid';
22
-
23
- async function run() {
24
- const connection = await Durable.Connection.connect({
25
- class: Redis,
26
- options: {
27
- host: 'localhost',
28
- port: 6379,
29
- },
30
- });
31
-
32
- const client = new Durable.Client({
33
- connection,
34
- });
35
-
36
- const handle = await client.workflow.start({
37
- args: ['HotMesh'],
38
- taskQueue: 'hello-world',
39
- workflowName: 'example',
40
- workflowId: 'workflow-' + nanoid(),
41
- });
42
-
43
- console.log(`Started workflow ${handle.workflowId}`);
44
- console.log(await handle.result());
45
- }
46
-
47
- run().catch((err) => {
48
- console.error(err);
49
- process.exit(1);
50
- });
51
-
52
- */
12
+ import { Search } from './search';
53
13
 
54
14
  export class ClientService {
55
15
 
@@ -96,7 +56,7 @@ export class ClientService {
96
56
  * this method will configure the search index for the workflow.
97
57
  */
98
58
  configureSearchIndex = async (hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void> => {
99
- if (search) {
59
+ if (search?.schema) {
100
60
  const store = hotMeshClient.engine.store;
101
61
  const schema: string[] = [];
102
62
  for (const [key, value] of Object.entries(search.schema)) {
@@ -148,6 +108,13 @@ export class ClientService {
148
108
  SUBSCRIBES_TOPIC,
149
109
  payload,
150
110
  context as JobState);
111
+ if (jobId && options.search?.data) {
112
+ //job successfully kicked off; there is default job data to persist
113
+ const search = new Search(jobId, hotMeshClient);
114
+ for (const [key, value] of Object.entries(options.search.data)) {
115
+ search.set(key, value);
116
+ }
117
+ }
151
118
  return new WorkflowHandleService(hotMeshClient, workflowTopic, jobId);
152
119
  },
153
120
 
@@ -15,43 +15,14 @@ import {
15
15
  Registry,
16
16
  WorkerConfig,
17
17
  WorkerOptions,
18
- WorkflowDataType } from "../../types/durable";
18
+ WorkflowDataType,
19
+ WorkflowSearchOptions} from "../../types/durable";
19
20
  import { RedisClass, RedisOptions } from '../../types/redis';
20
21
  import {
21
22
  StreamData,
22
23
  StreamDataResponse,
23
24
  StreamStatus } from '../../types/stream';
24
-
25
- /*
26
- Here is an example of how the methods in this file are used:
27
-
28
- ./worker.ts
29
-
30
- import { Durable } from '@hotmeshio/hotmesh';
31
- import Redis from 'ioredis'; //OR `import * as Redis from 'redis';`
32
-
33
- import * as workflows from './workflows';
34
-
35
- async function run() {
36
- const worker = await Durable.Worker.create({
37
- connection: {
38
- class: Redis,
39
- options: {
40
- host: 'localhost',
41
- port: 6379,
42
- },
43
- },
44
- taskQueue: 'hello-world',
45
- workflow: workflows.example,
46
- });
47
- await worker.run();
48
- }
49
-
50
- run().catch((err) => {
51
- console.error(err);
52
- process.exit(1);
53
- });
54
- */
25
+ import { KeyService, KeyType } from '../../modules/key';
55
26
 
56
27
  export class WorkerService {
57
28
  static activityRegistry: Registry = {}; //user's activities
@@ -112,6 +83,38 @@ export class WorkerService {
112
83
  return WorkerService.activityRegistry;
113
84
  }
114
85
 
86
+ /**
87
+ * For those deployments with a redis stack backend (with the FT module),
88
+ * this method will configure the search index for the workflow.
89
+ */
90
+ //todo: bind this to the Search service; update constructor to expect hotMeshClient as first param (id is optional
91
+ //refactor and delete other one as well)
92
+ static async configureSearchIndex(hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void> {
93
+ if (search?.schema) {
94
+ const store = hotMeshClient.engine.store;
95
+ const schema: string[] = [];
96
+ for (const [key, value] of Object.entries(search.schema)) {
97
+ //prefix with a comma (avoids collisions with hotmesh reserved words)
98
+ schema.push(`_${key}`);
99
+ schema.push(value.type);
100
+ if (value.sortable) {
101
+ schema.push('SORTABLE');
102
+ }
103
+ }
104
+ try {
105
+ const keyParams = {
106
+ appId: hotMeshClient.appId,
107
+ jobId: ''
108
+ }
109
+ const hotMeshPrefix = KeyService.mintKey(hotMeshClient.namespace, KeyType.JOB_STATE, keyParams);
110
+ const prefixes = search.prefix.map((prefix) => `${hotMeshPrefix}${prefix}`);
111
+ await store.exec('FT.CREATE', `${search.index}`, 'ON', 'HASH', 'PREFIX', prefixes.length, ...prefixes, 'SCHEMA', ...schema);
112
+ } catch (err) {
113
+ hotMeshClient.engine.logger.info('durable-client-search-err', { err });
114
+ }
115
+ }
116
+ }
117
+
115
118
  static async create(config: WorkerConfig) {
116
119
  //always call `registerActivities` before `import`
117
120
  WorkerService.connection = config.connection;
@@ -125,6 +128,7 @@ export class WorkerService {
125
128
  const worker = new WorkerService();
126
129
  worker.activityRunner = await worker.initActivityWorker(config, activityTopic);
127
130
  worker.workflowRunner = await worker.initWorkflowWorker(config, workflowTopic, workflowFunction);
131
+ WorkerService.configureSearchIndex(worker.workflowRunner, config.search)
128
132
  await WorkerService.activateWorkflow(worker.workflowRunner);
129
133
  return worker;
130
134
  }
@@ -10,35 +10,6 @@ import { ACTIVITY_PUBLISHES_TOPIC, ACTIVITY_SUBSCRIBES_TOPIC, SLEEP_SUBSCRIBES_T
10
10
  import { DurableIncompleteSignalError, DurableSleepError, DurableWaitForSignalError } from '../../modules/errors';
11
11
  import { Search } from './search';
12
12
 
13
- /*
14
- `proxyActivities` returns a wrapped instance of the
15
- target activity, so that when the workflow calls a
16
- proxied activity, it is actually calling the proxy
17
- function, which in turn calls the activity function.
18
-
19
- Here is an example of how the methods in this file are used:
20
-
21
- ./workflows.ts
22
-
23
- import { Durable } from '@hotmeshio/hotmesh';
24
- import * as activities from './activities';
25
-
26
- const { greet } = Durable.workflow.proxyActivities<typeof activities>({
27
- activities: activities,
28
- startToCloseTimeout: '1 minute',
29
- retryPolicy: {
30
- initialInterval: '5 seconds', // Initial delay between retries
31
- maximumAttempts: 3, // Max number of retry attempts
32
- backoffCoefficient: 2.0, // Backoff factor for delay between retries: delay = initialInterval * (backoffCoefficient ^ retry_attempt)
33
- maximumInterval: '30 seconds', // Max delay between retries
34
- },
35
- });
36
-
37
- export async function example(name: string): Promise<string> {
38
- return await greet(name);
39
- }
40
- */
41
-
42
13
  export class WorkflowService {
43
14
 
44
15
  /**
@@ -98,7 +69,7 @@ export class WorkflowService {
98
69
  return proxy;
99
70
  }
100
71
 
101
- static async data(command: 'del' | 'get' | 'set' | 'incr' | 'mult', ...args: string[]): Promise<number | boolean | string> {
72
+ static async search(): Promise<Search> {
102
73
  const store = asyncLocalStorage.getStore();
103
74
  if (!store) {
104
75
  throw new Error('durable-store-not-found');
@@ -106,26 +77,8 @@ export class WorkflowService {
106
77
  const workflowId = store.get('workflowId');
107
78
  const workflowTopic = store.get('workflowTopic');
108
79
 
109
- try {
110
- const hotMeshClient = await WorkerService.getHotMesh(workflowTopic);
111
- const search = new Search(workflowId, hotMeshClient);
112
- if (command === 'get') {
113
- return await search.get(args[0]) as string;
114
- } else if (command === 'set') {
115
- await search.set(args[0], args[1]);
116
- return true;
117
- } else if (command === 'del') {
118
- await search.del(args[0]);
119
- return true;
120
- } else if (command === 'incr') {
121
- return await search.incr(args[0], Number(args[1])) as number;
122
- } else if (command === 'mult') {
123
- return await search.mult(args[0], Number(args[1])) as number;
124
- }
125
- } catch (e) {
126
- console.error(e);
127
- return '';
128
- }
80
+ const hotMeshClient = await WorkerService.getHotMesh(workflowTopic);
81
+ return new Search(workflowId, hotMeshClient);
129
82
  }
130
83
 
131
84
  static async sleep(duration: string): Promise<number> {
package/types/durable.ts CHANGED
@@ -8,9 +8,10 @@ type WorkflowConfig = {
8
8
  }
9
9
 
10
10
  type WorkflowSearchOptions = {
11
- index: string; //FT index name (myapp:myindex)
12
- prefix: string[]; //FT prefixes (['myapp:myindex:prefix1', 'myapp:myindex:prefix2'])
13
- schema: Record<string, {type: 'TEXT' | 'NUMERIC' | 'TAG', sortable: boolean}>;
11
+ index?: string; //FT index name (myapp:myindex)
12
+ prefix?: string[]; //FT prefixes (['myapp:myindex:prefix1', 'myapp:myindex:prefix2'])
13
+ schema?: Record<string, {type: 'TEXT' | 'NUMERIC' | 'TAG', sortable: boolean}>;
14
+ data?: Record<string, string>;
14
15
  }
15
16
 
16
17
  type WorkflowOptions = {
@@ -66,6 +67,7 @@ type WorkerConfig = {
66
67
  taskQueue: string; //`subscribes` in the YAML (e.g, 'hello-world')
67
68
  workflow: Function; //target function to run
68
69
  options?: WorkerOptions;
70
+ search?: WorkflowSearchOptions;
69
71
  }
70
72
 
71
73
  type WorkerOptions = {