Skip to main content
Version: 1.4

Session

Introduction

Conversations may happen in a 1 on 1 chat or even in a channel with thousands of people in there. So, Bottender provides a mechanism called session to distinguish different conversations and store temporary data on the corresponding conversation. The session mechanism in Bottender bots is similar to the session mechanism in typical web servers.

Before using the session, you may want to know the following terminologies:

Session State

Session state is the temporary data stored on the corresponding conversation. You can provide customized user experience with session state. For example, you can use session state to count the number of the received messages.

A Counting Bot Example

Considering a counting bot which replies the number of message events it received, for example:

You > Hi
Bot > Count: 1
You > Hi
Bot > Count: 2

In this section, we will explain how to use the state correctly to build a counter. It begins with a count state variable, which is updated when the bot receives an event.

Let's start with a static Bottender action as follows:

async function EventCount(context) {
await context.sendText('Count: 1');
}

Adding State to the Conversation

  1. Set initial state in the bottender.config.js file:
module.exports = {
initialState: {
count: 0,
},
};

After adding the above settings, Bottender sets the initial state to the specified object for the new conversation session.

  1. Access state value using context.state:
async function EventCount(context) {
const count = context.state.count + 1;
await context.sendText(`Count: ${count}`);
}

Even though we use the state variable to render the message content, it always gets Count: 1 as a result. That's why step 3 is necessary.

  1. Set state value using context.setState():
async function EventCount(context) {
const count = context.state.count + 1;

context.setState({
count,
});

await context.sendText(`Count: ${count}`);
}

Then it works as expected.

Note: don't modify state directly using this.state.stateKey = stateValue;, it may cause unexpected behavior in the future.

State Updates are Merged

When you call setState(), Bottender shallow merges the object you provide into the current state.

context.state; // { count: 1 }

context.setState({
myObject: {},
});

context.state; // { count: 1, myObject: {} }

If you want to do a deeper merge, you need to do it explicitly:

context.setState({
myObject: {
...context.myObject,
key: value,
},
});

Debug State in Console Mode

In Console Mode, you can leverage the convenient built-in command - /state to help you debug you state transition:

You > /state

The /state command formats the state with JSON.stringify() and send the result as a bot message to you:

Bot > { "count": 1 }

Session ID

Every session has a unique identifier. You can get the unique identifier on the context by accessing context.session.id. For example, you may let your bot replies with the platform and session ID information to the user:

module.exports = async function App(context) {
await context.sendText(`Platform: ${context.platform}`);
await context.sendText(`Session ID: ${context.session.id}`);
};

To avoid ID conflict among platforms, Bottender combines the name of the platform and the session key to create the unique session ID. For example:

  • telegram:16423... on Telegram
  • line:U4af4980629... on LINE

To support all kinds of 1 on 1 chats and channel chats on all platforms, Bottender gets session keys from user IDs, channel IDs, group IDs, room IDs, or whatever that Bottender can use to distinguish the conversations.

For example, the LINE platform defines three types of sources (user, group, and room) in the LINE official document:

  • If an event comes from a user, the session key is the value of source.userId, so the entire session ID looks like: line:U4af4980629....
  • If an event comes from a group, the session key is the value of source.groupId, so the entire session ID looks like: line:Ca56f94637c....
  • If an event comes from a room, the session key is the value of source.roomId, so the entire session ID looks like: line:Ra8dbf4673c....

Session Storage

Since HTTP driven apps are stateless, the mission of sessions is to store the context of users during conversations.

Configuring Session Driver

The session driver configuration option defines where session data are stored for each conversation. To set the session driver, edit the session.driver field in the bottender.config.js file:

// bottender.config.js

module.exports = {
session: {
driver: 'memory',
stores: {
memory: {
maxSize: 500,
},
file: {
dirname: '.sessions',
},
redis: {
port: 6379,
host: '127.0.0.1',
password: 'auth',
db: 0,
},
mongo: {
url: 'mongodb://localhost:27017',
collectionName: 'sessions',
},
},
},
};

Bottender ships with several great drivers out of the box:

  • memory - sessions are stored in memory with LRU cache and not persistent.
  • file - sessions are stored in the files placed in the .sessions directory.
  • redis - sessions are stored in a Redis database.
  • mongo - sessions are stored in a MongoDB database.

Using Different Session Driver Based on NODE_ENV

We recommend using memory as the session driver in development for shorter iteration. By restarting the process, you can reset the session store completely.

Also, you can determine which session driver to use in development or production separately by using an environment variable:

// bottender.config.js

module.exports = {
session: {
driver: process.env.NODE_ENV === 'production' ? 'mongo' : 'memory',
// ...
},
};

Setting the Session Expiration Time

You can specify an explicit session expiration time to reset the state. It makes a bot more human-like by forgetting (re-initializing) the state after the conversation has been inactive for a while.

By default, Bottender never expires the stored sessions. To set explicit session expiration time, add the session.expiresIn setting in your bottender.config.js file:

// bottender.config.js

module.exports = {
session: {
driver: 'memory',
expiresIn: 15, // 15 minutes
// ...
},
};

With the above settings, the users get a new session and state after 15 minutes of user inactive.