I am trying to run a Mastodon bot using scheduled functions.
My site name is: oblique-questions-bot.netlify.app
The source code is here: GitHub - matthewmcvickar/oblique-questions-bot: A bot that posts questions without context.
I think I have the scheduled function set up correctly, all of which can be seen in that GitHub repo:
- I am exporting a function in the root
./bot.js
file calleddoPost()
. - I have a
./netlify.toml
file with the cron time set. - I have a
./netlify/functions/do-post.js
file that imports thedoPost()
function and executes it.
Unfortunately, the function is only executing in part. The text for the post is prepared, but it doesn’t connect and post to Mastodon.
Here’s the log of the most recent execution of the function. I don’t know why it executes three times, and I don’t know why it’s not going any further than preparing the status text:
Jan 29, 04:00:03 PM: a8ebbbbf INFO ---
Jan 29, 04:00:03 PM: a8ebbbbf INFO RUNNING SCHEDULED FUNCTION:
Jan 29, 04:00:03 PM: a8ebbbbf INFO CALLING doPost() FUNCTION:
Jan 29, 04:00:03 PM: a8ebbbbf INFO NOW ATTEMPTING TO POST: Bought their possessions?
Jan 29, 04:00:04 PM: a8ebbbbf Duration: 36.97 ms Memory Usage: 107 MB Init Duration: 419.02 ms
Jan 29, 04:00:05 PM: 6a7ce182 INFO ---
Jan 29, 04:00:05 PM: 6a7ce182 INFO RUNNING SCHEDULED FUNCTION:
Jan 29, 04:00:05 PM: 6a7ce182 INFO CALLING doPost() FUNCTION:
Jan 29, 04:00:05 PM: 6a7ce182 INFO NOW ATTEMPTING TO POST: Understood what?
Jan 29, 04:00:05 PM: 6a7ce182 Duration: 4.72 ms Memory Usage: 107 MB
Jan 29, 04:00:07 PM: 54bcd4a4 INFO ---
Jan 29, 04:00:07 PM: 54bcd4a4 INFO RUNNING SCHEDULED FUNCTION:
Jan 29, 04:00:07 PM: 54bcd4a4 INFO CALLING doPost() FUNCTION:
Jan 29, 04:00:07 PM: 54bcd4a4 INFO NOW ATTEMPTING TO POST: Garthie, do you realise what it means?
Jan 29, 04:00:07 PM: 54bcd4a4 Duration: 3.97 ms Memory Usage: 107 MB
I have tested the function locally using netlify functions:serve
on the command line and it works as expected:
Request from ::ffff:127.0.0.1: GET /.netlify/functions/do-post
---
RUNNING SCHEDULED FUNCTION:
Received event: {
path: '/.netlify/functions/do-post',
httpMethod: 'GET',
queryStringParameters: {},
multiValueQueryStringParameters: {},
headers: {
host: 'localhost:9999',
'user-agent': 'Netlify Clockwork',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate, br',
dnt: '1',
connection: 'keep-alive',
cookie: 'io=V4kWbrwdCv6BmVz7AAAK; local_adminer_session=24271; adminer_sid=2ae2da35383be1267510b8b3b85a32ba',
'upgrade-insecure-requests': '1',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'if-none-match': 'W/"128-06BYhxtJ8MRp/hknWZwCKtsq4R8"',
'client-ip': '127.0.0.1',
'X-NF-Event': 'schedule'
},
multiValueHeaders: {
host: [ 'localhost:9999' ],
'user-agent': [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0'
],
accept: [
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8'
],
'accept-language': [ 'en-US,en;q=0.5' ],
'accept-encoding': [ 'gzip, deflate, br' ],
dnt: [ '1' ],
connection: [ 'keep-alive' ],
cookie: [
'io=V4kWbrwdCv6BmVz7AAAK; local_adminer_session=24271; adminer_sid=2ae2da35383be1267510b8b3b85a32ba'
],
'upgrade-insecure-requests': [ '1' ],
'sec-fetch-dest': [ 'document' ],
'sec-fetch-mode': [ 'navigate' ],
'sec-fetch-site': [ 'none' ],
'sec-fetch-user': [ '?1' ],
'if-none-match': [ 'W/"128-06BYhxtJ8MRp/hknWZwCKtsq4R8"' ],
'client-ip': [ '127.0.0.1' ]
},
body: '{"next_run":"2023-01-30T04:00:00.000Z"}',
isBase64Encoded: false,
rawUrl: 'http://localhost:9999/.netlify/functions/do-post',
rawQuery: ''
}
In context: {
done: [Function: bound ],
fail: [Function: bound ],
succeed: [Function: bound ],
getRemainingTimeInMillis: [Function: bound ],
callbackWaitsForEmptyEventLoop: false,
functionName: 'handler',
functionVersion: '1.0',
invokedFunctionArn: 'arn:aws:lambda:us-east-1:902923746778:function:handler:1.0',
memoryLimitInMB: '457',
awsRequestId: '018bf8a6-0e81-10ea-6d54-ec5124fdf3c7',
logGroupName: 'Group name',
logStreamName: 'Stream name',
identity: null,
clientContext: {},
_stopped: false
}
CALLING doPost() FUNCTION:
NOW ATTEMPTING TO POST: Are we not to be friends?
Response with status 304 in 220 ms.
LOGGING IN TO MASTODON: Client {
http: HttpNativeImpl {
serializer: SerializerNativeImpl {},
config: MastoConfig {
props: [Object],
serializer: SerializerNativeImpl {}
},
logger: LoggerConsoleImpl { logLevel: [LogLevel] }
},
ws: WsNativeImpl {
config: MastoConfig {
props: [Object],
serializer: SerializerNativeImpl {}
},
serializer: SerializerNativeImpl {},
logger: LoggerConsoleImpl { logLevel: [LogLevel] }
},
config: MastoConfig {
props: {
url: 'https://botsin.space',
accessToken: 'UI-lk2EbIdAiGTkBxAB4p8BNv5eGp9vYEL381e_blwI',
version: [SemVer2],
streamingApiUrl: 'wss://botsin.space'
},
serializer: SerializerNativeImpl {}
},
logger: LoggerConsoleImpl { logLevel: LogLevel { level: 12 } },
v1: AggregateRepository {
http: HttpNativeImpl {
serializer: SerializerNativeImpl {},
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
config: MastoConfig {
props: [Object],
serializer: SerializerNativeImpl {}
},
logger: LoggerConsoleImpl { logLevel: [LogLevel] },
admin: AggregateRepositoryAdmin {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl],
accounts: [AccountRepository2],
canonicalEmailBlocks: [CanonicalEmailBlockRepository],
dimensions: [DimensionRepository],
domainBlocks: [DomainBlockRepository2],
domainAllows: [DomainAllowRepository],
emailDomainBlocks: [EmailDomainBlockRepository],
ipBlocks: [IpBlockRepository],
measures: [MeasureRepository],
reports: [ReportRepository2],
retention: [RetentionRepository],
trends: [TrendRepository2]
},
stream: StreamRepository {
ws: [WsNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
accounts: AccountRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
announcements: AnnouncementRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
apps: AppRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
blocks: BlockRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
bookmarks: BookmarkRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
conversations: ConversationRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
customEmojis: CustomEmojiRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
directory: DirectoryRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
domainBlocks: DomainBlockRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
endorsements: EndorsementRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
favourites: FavouriteRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
featuredTags: FeaturedTagRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
filters: FilterRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
followRequests: FollowRequestRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
instances: InstanceRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
lists: ListRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
markers: MarkerRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
mediaAttachments: MediaAttachmentRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
mutes: MuteRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
notifications: NotificationRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
polls: PollRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
preferences: PreferenceRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
webPushSubscriptions: WebPushSubscriptionRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
reports: ReportRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
scheduledStatuses: ScheduledStatusRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
statuses: StatusRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
suggestions: SuggestionRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
timelines: TimelineRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
trends: TrendRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
email: EmailRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
tags: TagRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
followedTags: FollowedTagRepository {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
}
},
v2: AggregateRepository2 {
http: HttpNativeImpl {
serializer: SerializerNativeImpl {},
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
config: MastoConfig {
props: [Object],
serializer: SerializerNativeImpl {}
},
logger: LoggerConsoleImpl { logLevel: [LogLevel] },
filters: FilterRepository2 {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
instance: InstanceRepository2 {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
},
mediaAttachments: MediaAttachmentRepository2 {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl],
v1: [MediaAttachmentRepository]
},
suggestions: SuggestionRepository2 {
http: [HttpNativeImpl],
config: [MastoConfig],
logger: [LoggerConsoleImpl]
}
},
oauth: OAuthRepository {
http: HttpNativeImpl {
serializer: SerializerNativeImpl {},
config: [MastoConfig],
logger: [LoggerConsoleImpl]
}
}
}
RESULT OF ATTEMPT TO POST: {
id: '109775359056840661',
createdAt: '2023-01-30T00:37:28.113Z',
inReplyToId: null,
inReplyToAccountId: null,
sensitive: false,
spoilerText: '',
visibility: 'public',
language: 'en',
uri: 'https://botsin.space/users/obliquestions/statuses/109775359056840661',
url: 'https://botsin.space/@obliquestions/109775359056840661',
repliesCount: 0,
reblogsCount: 0,
favouritesCount: 0,
editedAt: null,
favourited: false,
reblogged: false,
muted: false,
bookmarked: false,
pinned: false,
content: '<p>Are we not to be friends?</p>',
filtered: [],
reblog: null,
application: {
name: 'Oblique Questions',
website: 'https://github.com/matthewmcvickar/oblique-questions-bot'
},
account: {
id: '86708',
username: 'obliquestions',
acct: 'obliquestions',
displayName: 'Oblique Questions',
locked: false,
bot: true,
discoverable: null,
group: false,
createdAt: '2018-11-14T00:00:00.000Z',
note: '<p>Questions without context, extracted from Project Gutenberg books.</p>',
url: 'https://botsin.space/@obliquestions',
avatar: 'https://files.botsin.space/accounts/avatars/000/086/708/original/4f7fd3c42f0938c8.png',
avatarStatic: 'https://files.botsin.space/accounts/avatars/000/086/708/original/4f7fd3c42f0938c8.png',
header: 'https://files.botsin.space/accounts/headers/000/086/708/original/7643860d3ae67d2d.png',
headerStatic: 'https://files.botsin.space/accounts/headers/000/086/708/original/7643860d3ae67d2d.png',
followersCount: 59,
followingCount: 2,
statusesCount: 7870,
lastStatusAt: '2023-01-30',
noindex: true,
emojis: [],
fields: [ [Object], [Object], [Object] ]
},
mediaAttachments: [],
mentions: [],
tags: [],
emojis: [],
card: null,
poll: null
}
SUCCESSFULLY POSTED TO MASTODON: https://botsin.space/@obliquestions/109775359056840661
Any ideas?