Skip to content

Implement Outstanding Operations management#99

Open
Lynesth wants to merge 7 commits into
python-smpplib:masterfrom
Lynesth:patch-10
Open

Implement Outstanding Operations management#99
Lynesth wants to merge 7 commits into
python-smpplib:masterfrom
Lynesth:patch-10

Conversation

@Lynesth

@Lynesth Lynesth commented Sep 7, 2019

Copy link
Copy Markdown
Contributor

According to the SMPP specification:

The maximum number of outstanding (i.e. unacknowledged) SMPP operations between an ESME and SMSC and vice versa is not specified explicitly in the SMPP Protocol Specification and will be governed by the SMPP implementation on the SMSC.
However, as a guideline it is recommended that no more than 10 (ten) SMPP messages are outstanding at any time.

This is how I implemented it for my needs. It seems to work fine on my end (~1500 SMS / day on average).
Let me know @eigenein @podshumok what you think about it.

@Lynesth

Lynesth commented Sep 7, 2019

Copy link
Copy Markdown
Contributor Author

That's the wrong implementation... Will fix it later, I gotta go.

@Lynesth

Lynesth commented Sep 12, 2019

Copy link
Copy Markdown
Contributor Author

It can only work in a threaded environment (threaded listen/poll).

I'm sure it isn't the best way to implement this, by far, but it gives a good idea of what needs to be done I think.

I'd like to ear your ideas on this @eigenein when you have time.

@eigenein

Copy link
Copy Markdown
Collaborator

Hi @Lynesth, sorry for the slow reaction, had tough time recently, just wanna keep you updated. I'll take a look within a week, most likely this Friday

Comment thread smpplib/client.py Outdated
consts.DESCRIPTIONS[consts.SMPP_ESME_RINVBNDSTS],
))

if self.max_outstanding_operations and p.command[-5:] != '_resp':

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to use pdu.is_request() and pdu.is_response() to tell if it's a response

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't notice those functions it'll be better indeed.

Comment thread smpplib/client.py Outdated
raise exceptions.ConnectionError()
sent += sent_last

if p.command[-5:] == '_resp':

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for is_response() test

Comment thread smpplib/client.py Outdated
Comment on lines +220 to +221
else:
self.outstanding_operations += 1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm, I don't really get this part. Why reading a PDU really increases the number?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case we are reading a PDU which isn't a response so it's the SMSC asking for something, so it is an outstanding operation until we actually answer it.

Comment thread smpplib/client.py Outdated
self.port = int(port)
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.timeout = timeout
self.outstanding_operations = 0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit afraid of the counter getting out of sync for requests/responses. Would it be smarter to keep a set of PDU sequence IDs? So, when you got a request PDU then you add its sequence ID to the set. For a response PDU you remove its sequence ID from the set. And to check you test length of the set. Then we're more safe in terms of lost packets and/or retries

By the way, I guess that unbind and disconnect handlers should reset the current outstanding operations counter/set. Otherwise, we may never get response for some unconfirmed PDUs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using a set is a good idea yes.

Regarding unbind/disconnect, it shouldn't reset it. Example:
I connect, send 10 submit_sm and then disconnect. When I reconnect 5 minutes later, the SMSC will actually send me 10 submit_sm_resp that were outstanding, using the same sequence numbers that were used to send the submit_sm.
We don't reset the sequence number on unbind/disconnect by default either, do we ?

Nevertheless it wouldn't be failproof in case the script gets killed or something so...

Comment thread smpplib/client.py

if self.max_outstanding_operations and p.command[-5:] != '_resp':
while self.outstanding_operations >= self.max_outstanding_operations:
sleep(.1)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably use threading.Event.wait() to block here. Then response handling code could flag the event to unblock the loop here. This way I wouldn't need the sleep

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never used events before, will take a look a that, thank you.

@Lynesth

Lynesth commented Oct 5, 2019

Copy link
Copy Markdown
Contributor Author

@eigenein Thank you for your comments, I will answer to each individually.

Comment thread smpplib/client.py
except KeyError:
self.logger.warning('Failed to unregistered outstanding operation {}'.format(operation))
else:
operation = '{}{}'.format('C' if sending else 'S', pdu.sequence)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated line which is used in both branches. Could you move it right above the if?

Comment thread smpplib/client.py
"""Send PDU to the SMSC"""

if self.state not in consts.COMMAND_STATES[p.command]:
if self.state not in consts.COMMAND_STATES[pdu.command]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for renaming that :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants