|
| 1 | +<a name="0.15.0"></a> |
| 2 | +# [0.15.0](https://github.com/moleculerjs/moleculer/compare/v0.14.29...v0.15.0) (2023-xx-xx) |
| 3 | + |
| 4 | +[**Migration guide from 0.14 to 0.15**](https://github.com/moleculerjs/moleculer/blob/next/docs/MIGRATION_GUIDE_0.15.md) |
| 5 | + |
| 6 | +# Breaking changes |
| 7 | + |
| 8 | +## Minimum Node 18 |
| 9 | +The minimum supported Node version is changed from Node 10 to Node 18. |
| 10 | + |
| 11 | +## Communication protocol has been changed |
| 12 | +The Moleculer communication protocol has been changed. The new protocol version is `5`. However all schema-based serializer has been removed from the core repo. It means v0.15 Moleculer nodes will able to communicate with v0.14 nodes, if you disable version checking in broker options. |
| 13 | + |
| 14 | +## Schema-based serializers (ProtoBuf, Avro, Thrift) are removed |
| 15 | + |
| 16 | +The reason is desribed in this issue: https://github.com/moleculerjs/moleculer/issues/882 |
| 17 | + |
| 18 | +If you use one of those, you should change it to one of these schemaless serializers: MsgPack, Notepack.io, JSON, JSONExt, CBOR |
| 19 | + |
| 20 | +## Action streaming |
| 21 | + |
| 22 | +The built-in `Stream` sending has been rewritten. Now it accepts `params` besides the `Stream` instance. |
| 23 | +The `Stream` parameter moved from `ctx.params` into calling options under a `stream` property. |
| 24 | + |
| 25 | +### New way to send a stream with extra parameters |
| 26 | +The stream instance is passed as a calling options, so you can use `ctx.params` as a normal action call. |
| 27 | + |
| 28 | +```js |
| 29 | +ctx.call("file.save", { filename: "as.txt" }, { stream: fs.createReadStream() }); |
| 30 | +``` |
| 31 | + |
| 32 | +### New way to receive a stream |
| 33 | + |
| 34 | +```js |
| 35 | +// file.service.js |
| 36 | +module.exports = { |
| 37 | + name: "file", |
| 38 | + actions: { |
| 39 | + save(ctx) { |
| 40 | + // The stream is in Context directly |
| 41 | + const stream = ctx.stream; |
| 42 | + const s = fs.createWriteStream(ctx.params.filename); |
| 43 | + stream.pipe(s); |
| 44 | + } |
| 45 | + } |
| 46 | +}; |
| 47 | +``` |
| 48 | + |
| 49 | +## Removed deprecated functions and signatures |
| 50 | + |
| 51 | +### Removed deprecated event sending method signature |
| 52 | + |
| 53 | +In previous versions, the `emit`, `broadcast` and `broadcastLocal` methods accept a group `String` or groups as `Array<String>` as third arguments, instead of an `opts`. |
| 54 | +This signature is removed, you should always pass an `opts` object as 3rd argument. |
| 55 | + |
| 56 | +### Removed deprecated middleware as a `Function` |
| 57 | +We removed and old and deprecated middleware signature where the middleware was `localAction` function. Now `ServiceBroker` accepts middleware as `Object` only. |
| 58 | + |
| 59 | +### Removed deprecated `getLocalService` signature. |
| 60 | + |
| 61 | +The `broker.getLocalService` supports only `getLocalService(name|obj)` without second `version` parameter. If you want to get a versioned service, use the `v1.posts` argument or as object `{ name: "posts", version: 1}` |
| 62 | + |
| 63 | +### Removed `Service` constructor 3rd argument. |
| 64 | + |
| 65 | +The `Service` constructor had a 3rd argument as `schemaMods` which was deprecated because you should use `mixins` instead modifier schemas. |
| 66 | + |
| 67 | +## Garbage collector and event-loop metrics removed |
| 68 | + |
| 69 | +Since `gc-stats` and `event-loop-stats` native libraries are not maintained and they are not compatible with newer Node versions, they are removed from the built-in metrics. |
| 70 | + |
| 71 | +**Removed metrics:** |
| 72 | +- `process.gc.time` |
| 73 | +- `process.gc.total.time` |
| 74 | +- `process.gc.executed.total` |
| 75 | +- `process.eventloop.lag.min` |
| 76 | +- `process.eventloop.lag.avg` |
| 77 | +- `process.eventloop.lag.max` |
| 78 | +- `process.eventloop.lag.count` |
| 79 | + |
| 80 | +## Removed STAN (NATS Streaming) transporter |
| 81 | + |
| 82 | +The STAN (NATS Streaming) transporter has been removed while it's deprecated and not supported by the NATS.io, as well. More info: https://nats-io.gitbook.io/legacy-nats-docs/nats-streaming-server-aka-stan |
| 83 | + |
| 84 | +## Rewritten Kafka transporter (based on kafkajs) |
| 85 | + |
| 86 | +The previous `kafka-node` based transporter has been rewritten to a `kafkajs` based transporter. It means, you should migrate your Kafka Transporter options. |
| 87 | + |
| 88 | +```js |
| 89 | +// moleculer.config.js |
| 90 | +module.exports = { |
| 91 | + transporter: { |
| 92 | + type: "Kafka", |
| 93 | + options: { |
| 94 | + // KafkaClient options. More info: https://kafka.js.org/docs/configuration |
| 95 | + client: { |
| 96 | + brokers: [/*...*/] |
| 97 | + }, |
| 98 | + |
| 99 | + // KafkaProducer options. More info: https://kafka.js.org/docs/producing#options |
| 100 | + producer: {}, |
| 101 | + |
| 102 | + // ConsumerGroup options. More info: https://kafka.js.org/docs/consuming#a-name-options-a-options |
| 103 | + consumer: {}, |
| 104 | + |
| 105 | + // Advanced options for `send`. More info: https://kafka.js.org/docs/producing#producing-messages |
| 106 | + publish: {}, |
| 107 | + |
| 108 | + // Advanced message options for `send`. More info: https://kafka.js.org/docs/producing#message-structure |
| 109 | + publishMessage: { |
| 110 | + partition: 0 |
| 111 | + } |
| 112 | + } |
| 113 | + } |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +About new configuration options, check this documentation: https://kafka.js.org/docs/configuration |
| 118 | + |
| 119 | +## Removed legacy NATS library ([email protected]) implementation |
| 120 | + |
| 121 | +The legacy `[email protected]` transporter implementation is removed. This version supports only `[email protected]` library. |
| 122 | + |
| 123 | +## The Fastest Validator options changed. |
| 124 | + |
| 125 | +In 0.15 the `useNewCustomCheckFunction` default value is changed from `false` to `true`. It means, if you have old custom checker function in your parameter validation schemas, you should rewrite it to the new custom check function form. |
| 126 | + |
| 127 | +You can see example about migration here: https://github.com/icebob/fastest-validator/blob/master/CHANGELOG.md#new-custom-function-signature |
| 128 | + |
| 129 | +## Rewritten Typescript definition files |
| 130 | + |
| 131 | +The previously used huge one-file `index.d.ts` file has been rewritten and separated to multiple `d.ts` files, all are placed besides the source file. It may causes breaking changes in Typescript projects. |
| 132 | + |
| 133 | + |
| 134 | +# New features |
| 135 | + |
| 136 | +## New JSON Extended serializer |
| 137 | + |
| 138 | +We implemented a new JSON serializer which unlike the native JSON serializer, it supports serializing `Buffer`, `BigInt`, `Date`, `Map`, `Set` and `RegExp` classes, as well. |
| 139 | + |
| 140 | +### Example |
| 141 | + |
| 142 | +```js |
| 143 | +// moleculer.config.js |
| 144 | +module.exports = { |
| 145 | + serializer: "JSONExt" |
| 146 | +} |
| 147 | +``` |
| 148 | + |
| 149 | +### Custom extensions |
| 150 | + |
| 151 | +You can extend the serializer with custom types. |
| 152 | + |
| 153 | +#### Example to extend with a custom class serializing/deserializing |
| 154 | + |
| 155 | +```js |
| 156 | +// MyClass.js |
| 157 | +class MyClass { |
| 158 | + constructor(a, b) { |
| 159 | + this.a = a; |
| 160 | + this.b = b; |
| 161 | + } |
| 162 | +} |
| 163 | +``` |
| 164 | + |
| 165 | +```js |
| 166 | +// moleculer.config.js |
| 167 | +module.exports = { |
| 168 | + serializer: { |
| 169 | + type: "JSONExt", |
| 170 | + options: { |
| 171 | + customs: [ |
| 172 | + { |
| 173 | + // This is the identifier of the custom type |
| 174 | + prefix: "AB", |
| 175 | + |
| 176 | + // This function checks the type of JSON value |
| 177 | + check: v => v instanceof MyClass, |
| 178 | + |
| 179 | + // Serialize the custom class properties to a String |
| 180 | + serialize: v => v.a + "|" + v.b, |
| 181 | + |
| 182 | + // Deserialize the JSON string to custom class instance and set properties |
| 183 | + deserialize: v => { |
| 184 | + const [a, b] = v.split("|"); |
| 185 | + return new MyClass(parseInt(a), b); |
| 186 | + } |
| 187 | + } |
| 188 | + ] |
| 189 | + } |
| 190 | + } |
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +## New Request headers |
| 195 | + |
| 196 | +We added a new `headers` property in calling options and Context class to store meta information for an action calling or an event emitting. |
| 197 | + |
| 198 | +The difference between `headers` and `meta` is that the `meta` is always passed to all action calls in a chain and merged, the `headers` is transferred only to the actual action call and not passed to the nested calls. |
| 199 | + |
| 200 | +>Please note, header keys start with `$` means internal header keys (e.g. `$streamObjectMode`). We recommend to don't use this prefix for your keys to avoid conflicts. |
| 201 | +
|
| 202 | +### Set headers in action calls |
| 203 | + |
| 204 | +```js |
| 205 | +broker.call("posts.list", { limit: 100 }, { |
| 206 | + headers: { |
| 207 | + customProp: "customValue" |
| 208 | + } |
| 209 | +}); |
| 210 | +``` |
| 211 | + |
| 212 | +> You can use the same way for event emitting or broadcasting. |
| 213 | +
|
| 214 | +### Read headers inside action handler |
| 215 | + |
| 216 | +```js |
| 217 | +// posts.service.js |
| 218 | +module.exports = { |
| 219 | + name: "posts", |
| 220 | + actions: { |
| 221 | + list(ctx) { |
| 222 | + const customProp = ctx.headers.customProp; |
| 223 | + } |
| 224 | + } |
| 225 | +}; |
| 226 | +``` |
| 227 | + |
| 228 | +> You can use the same way in event handlers. |
| 229 | +
|
| 230 | +### Use header value in cache keys |
| 231 | + |
| 232 | +You can add headers values to the cache keys as well. For this, use `@` prefix |
| 233 | + |
| 234 | +```js |
| 235 | +// posts.service.js |
| 236 | +module.exports = { |
| 237 | + name: "posts", |
| 238 | + actions: { |
| 239 | + list: { |
| 240 | + cache: { |
| 241 | + keys: [ |
| 242 | + "limit", // value from `ctx.params` |
| 243 | + "#tenant", // value from `ctx.meta` |
| 244 | + "@customProp" // value from `ctx.headers` |
| 245 | + ] |
| 246 | + } |
| 247 | + handler(ctx) { |
| 248 | + const customProp = ctx.headers.customProp; |
| 249 | + } |
| 250 | + } |
| 251 | + } |
| 252 | +}; |
| 253 | +``` |
| 254 | +### Response headers |
| 255 | + |
| 256 | +The Moleculer protocol supports headers in response, as well (`ctx.responseHeaders`). But in normal way, you can't access to them in your services because you don't have pointer to the returned `Context` instance. So at present, it can be used by middlewares only. |
| 257 | + |
| 258 | +## Other changes |
| 259 | + |
| 260 | +### Better error handling in event handlers. |
| 261 | + |
| 262 | +!TODO! |
| 263 | + |
| 264 | +### Cacher changes |
| 265 | + |
| 266 | +#### The `getCacheKey` and `opts.keygen` signature has been changed |
| 267 | + |
| 268 | +Old signature: `getCacheKey(actionName, params, meta, keys, actionKeygen)` |
| 269 | + |
| 270 | +New signature: `getCacheKey(action, opts, ctx)` |
| 271 | + |
| 272 | + |
| 273 | +#### Added `missingResponse` option to cacher options |
| 274 | + |
| 275 | +In 0.14, you could not make a difference between the result cached value is `null` or it's not in the cache. Because both way, the `cacher.get` responded with `null`. |
| 276 | + |
| 277 | +In 0.15, if a cache key is not found in cache, it returns `undefined` by default, or you can change it with `missingResponse` option. |
| 278 | + |
| 279 | +**Example: using a custom symbol to detect missing entries** |
| 280 | + |
| 281 | +```js |
| 282 | +const missingSymbol = Symbol("MISSING"); |
| 283 | + |
| 284 | +// moleculer.config.js |
| 285 | +module.exports = { |
| 286 | + cacher: { |
| 287 | + type: "Memory", |
| 288 | + options: { |
| 289 | + missingResponse: missingSymbol |
| 290 | + } |
| 291 | + } |
| 292 | +} |
| 293 | + |
| 294 | +// Get data from cache |
| 295 | + |
| 296 | +const res = await cacher.get("not-existing-key"); |
| 297 | +if (res === cacher.opts.missingSymbol) { |
| 298 | + console.log("It's not cached."); |
| 299 | +} |
| 300 | +``` |
| 301 | + |
| 302 | +### Cache key generation changed |
| 303 | + |
| 304 | +There are some changes in the serialized values in the cache keys. In previous versions, the `null` and `undefined` values were serialized as `null`, and `"null"` as string also serialized to `null`. |
| 305 | +In 0.15, string values are wrapped into quotes, the `null` is `null` and `undefined` is serialized as `undefined`, so similar serialized values. |
| 306 | + |
| 307 | +These changes means the 0.15 cachers create different cache keys than 0.14 cachers. |
| 308 | + |
| 309 | + |
| 310 | +-------------------------------------------------- |
1 | 311 | <a name="Unreleased"></a>
|
2 | 312 | # [Unreleased](https://github.com/moleculerjs/moleculer/compare/v0.14.29...master)
|
3 | 313 |
|
|
0 commit comments