Skip to content

socket timeout or workaround #2073

Closed
Closed
@ssube

Description

@ssube

Hi, I'm looking to use the Feather M4 Express and Ethernet FeatherWing as a way to collect I2C sensor data with Prometheus and threw together a very small HTTP server for that purpose. It works pretty well with light traffic, but if the socket.accept waits too long for an incoming request, the board seems to fall off the network and my code soft-reboots without raising an error:

Headers: {'http': 'HTTP/1.1', 'method': 'GET', 'path': '/favicon.ico'}
Connection: ('10.2.1.193', 8080)

Code done running. Waiting for reload.
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
['0x40', '0x77']
Online: True
Network: ('0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0')

When no requests are incoming, I would like the socket.accept to break after a few seconds to let the network driver run and take another sample from the sensors.

The docs and source seem to support socket.settimeout but it appears to invoke a method (syscall?) on the NIC, which throws:

Online: True
Network: ('0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0')
Online: True
Network: ('10.2.2.254', '255.255.0.0', '10.2.1.1', '0.0.0.0')
Binding: 10.2.2.254:8080
Unable to set socket timeout: [Errno 22] Invalid argument

Is there a way to make the socket timeout, have a timer interrupt it, or work around this somehow?

Running:

Adafruit CircuitPython 4.1.0 on 2019-08-02; Adafruit Feather M4 Express with samd51j19

My socket setup code is:

def start_http_server(port, address='0.0.0.0'):
    bind_address = (address, port)

    http_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    http_socket.bind(bind_address)
    http_socket.listen(1)

    try:
        http_socket.settimeout(5.0)
    except OSError as err:
        print('Unable to set socket timeout:', err)

    return Server(http_socket)


class Server():
    http_socket = False

    def __init__(self, http_socket):
        self.http_socket = http_socket

    def accept(self, router):
        conn, addr = self.http_socket.accept()
        print('Connection: {}'.format(addr))

        req = conn.recv(1024).decode(http_encoding)
        req_headers = self.parse_headers(req)
        print('Headers: {}'.format(req_headers))

        handler = router.select(req_headers['method'], req_headers['path'])
        resp = handler(req_headers, '')


def main():
    ready = False
    bound = False

    registry = CollectorRegistry(namespace='prom_express')
    metric_gas = Gauge('gas',
                       'gas from the bme680 sensor', registry=registry)
    metric_humidity = Gauge('humidity',
                            'humidity from both sensors', ['sensor'], registry=registry)
    metric_pressure = Gauge('pressure',
                            'pressure from the bme680 sensor', registry=registry)
    metric_temperature = Gauge('temperature',
                               'temperature from both sensors', ['sensor'], registry=registry)

    def prom_handler(headers, body):
        return {
            'status': '200 OK',
            'content': '\r\n'.join(registry.print()),
        }

    router = Router([
        ('GET', '/metrics', prom_handler),
    ])
    server = False

    rgb[0] = RED  # starting
    while not ready:
        ready = check_network(eth)
        led.value = ready

    rgb[0] = BLUE  # connected
    while not bound:
        server, bound = bind_server(eth)

    rgb[0] = GREEN  # ready
    while True:
        metric_gas.set(sensor_bme680.gas)
        metric_humidity.labels('bme680').set(sensor_bme680.humidity)
        metric_humidity.labels('si7021').set(sensor_si7021.relative_humidity)
        metric_pressure.set(sensor_bme680.pressure)
        metric_temperature.labels('bme680').set(sensor_bme680.temperature)
        metric_temperature.labels('si7021').set(sensor_si7021.temperature)

        try:
            server.accept(router)
        except OSError as err:
            print('Error accepting request: {}'.format(err))
            server, bound = bind_server(eth)
        except Exception as err:
            print('Unknown error: {}'.format(err))

With a more complete example here: https://github.com/ssube/prometheus_express/blob/master/examples/feather-m4-i2c.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions